/* 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.
#include "rtl.h"
#include "output.h"
#include "toplev.h"
-#include "varray.h"
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
extern struct obstack *current_obstack;
-extern tree abort_fndecl;
#include "stack.h"
#define search_level stack_level
static struct search_level *search_stack;
-static tree get_abstract_virtuals_1 PROTO((tree, int, 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 is_subobject_of_p PROTO((tree, tree));
-static int hides PROTO((tree, tree));
-static tree virtual_context PROTO((tree, tree, tree));
-static tree dfs_check_overlap PROTO((tree, void *));
-static tree dfs_no_overlap_yet PROTO((tree, void *));
-static void envelope_add_decl PROTO((tree, tree, tree *));
+static tree next_baselink PARAMS ((tree));
+static tree get_vbase_1 PARAMS ((tree, tree, unsigned int *));
+static tree lookup_field_1 PARAMS ((tree, tree));
+static tree convert_pointer_to_single_level PARAMS ((tree, tree));
+static int lookup_fnfields_here PARAMS ((tree, tree));
+static int is_subobject_of_p PARAMS ((tree, tree));
+static int hides PARAMS ((tree, tree));
+static tree virtual_context PARAMS ((tree, tree, tree));
+static tree dfs_check_overlap PARAMS ((tree, void *));
+static tree dfs_no_overlap_yet PARAMS ((tree, void *));
static int get_base_distance_recursive
- PROTO((tree, int, int, int, int *, tree *, tree,
+ PARAMS ((tree, int, int, int, int *, tree *, tree,
int, int *, int, int));
+static int dynamic_cast_base_recurse PARAMS ((tree, tree, int, tree *));
static void expand_upcast_fixups
- PROTO((tree, tree, tree, tree, tree, tree, tree *));
+ PARAMS ((tree, tree, tree, tree, tree, tree, tree *));
static void fixup_virtual_upcast_offsets
- PROTO((tree, tree, int, int, tree, tree, tree, tree,
+ PARAMS ((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 *));
-static tree dfs_debug_unmarkedp PROTO((tree, void *));
-static tree dfs_debug_mark PROTO((tree, void *));
-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 *));
-static tree dfs_get_vbase_types PROTO((tree, void *));
-static tree dfs_pushdecls PROTO((tree, void *));
-static tree dfs_compress_decls PROTO((tree, void *));
-static tree dfs_unuse_fields PROTO((tree, void *));
-static tree add_conversions PROTO((tree, void *));
-static tree get_virtuals_named_this PROTO((tree, tree));
-static tree get_virtual_destructor PROTO((tree, void *));
-static tree tree_has_any_destructor_p PROTO((tree, void *));
-static int covariant_return_p PROTO((tree, tree));
+static tree marked_vtable_pathp PARAMS ((tree, void *));
+static tree unmarked_vtable_pathp PARAMS ((tree, void *));
+static tree marked_new_vtablep PARAMS ((tree, void *));
+static tree unmarked_new_vtablep PARAMS ((tree, void *));
+static tree marked_pushdecls_p PARAMS ((tree, void *));
+static tree unmarked_pushdecls_p PARAMS ((tree, void *));
+#if 0
+static tree dfs_debug_unmarkedp PARAMS ((tree, void *));
+static tree dfs_debug_mark PARAMS ((tree, void *));
+#endif
+static tree dfs_find_vbases PARAMS ((tree, void *));
+static tree dfs_clear_vbase_slots PARAMS ((tree, void *));
+static tree dfs_init_vbase_pointers PARAMS ((tree, void *));
+static tree dfs_get_vbase_types PARAMS ((tree, void *));
+static tree dfs_push_type_decls PARAMS ((tree, void *));
+static tree dfs_push_decls PARAMS ((tree, void *));
+static tree dfs_unuse_fields PARAMS ((tree, void *));
+static tree add_conversions PARAMS ((tree, void *));
+static tree get_virtuals_named_this PARAMS ((tree, tree));
+static tree get_virtual_destructor PARAMS ((tree, void *));
+static tree tree_has_any_destructor_p PARAMS ((tree, void *));
+static int covariant_return_p PARAMS ((tree, tree));
+static int check_final_overrider PARAMS ((tree, tree));
static struct search_level *push_search_level
- PROTO((struct stack_level *, struct obstack *));
+ PARAMS ((struct stack_level *, struct obstack *));
static struct search_level *pop_search_level
- PROTO((struct stack_level *));
+ PARAMS ((struct stack_level *));
static tree bfs_walk
- PROTO((tree, tree (*) (tree, void *), tree (*) (tree, void *),
+ PARAMS ((tree, tree (*) (tree, void *), tree (*) (tree, void *),
void *));
-static tree lookup_field_queue_p PROTO((tree, void *));
-static tree lookup_field_r PROTO((tree, void *));
-static tree dfs_walk_real PROTO ((tree,
- tree (*) (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 tree shared_marked_p PROTO ((tree, void *));
-static tree shared_unmarked_p PROTO ((tree, void *));
-static int dependent_base_p PROTO ((tree));
-static tree dfs_accessible_queue_p PROTO ((tree, void *));
-static tree dfs_accessible_p PROTO ((tree, void *));
-static tree dfs_access_in_type PROTO ((tree, void *));
-static tree access_in_type PROTO ((tree, tree));
-static tree dfs_canonical_queue PROTO ((tree, void *));
-static tree dfs_assert_unmarked_p PROTO ((tree, void *));
-static void assert_canonical_unmarked PROTO ((tree));
+static tree lookup_field_queue_p PARAMS ((tree, void *));
+static tree lookup_field_r PARAMS ((tree, void *));
+static tree get_virtuals_named_this_r PARAMS ((tree, void *));
+static tree context_for_name_lookup PARAMS ((tree));
+static tree canonical_binfo PARAMS ((tree));
+static tree shared_marked_p PARAMS ((tree, void *));
+static tree shared_unmarked_p PARAMS ((tree, void *));
+static int dependent_base_p PARAMS ((tree));
+static tree dfs_accessible_queue_p PARAMS ((tree, void *));
+static tree dfs_accessible_p PARAMS ((tree, void *));
+static tree dfs_access_in_type PARAMS ((tree, void *));
+static tree access_in_type PARAMS ((tree, tree));
+static tree dfs_canonical_queue PARAMS ((tree, void *));
+static tree dfs_assert_unmarked_p PARAMS ((tree, void *));
+static void assert_canonical_unmarked PARAMS ((tree));
+static int protected_accessible_p PARAMS ((tree, tree, tree, tree));
+static int friend_accessible_p PARAMS ((tree, tree, tree, tree));
+static void setup_class_bindings PARAMS ((tree, int));
+static int template_self_reference_p PARAMS ((tree, tree));
+static void fixup_all_virtual_upcast_offsets PARAMS ((tree, tree));
+static tree dfs_mark_primary_bases PARAMS ((tree, void *));
+static tree get_shared_vbase_if_not_primary PARAMS ((tree, void *));
+static tree dfs_find_vbase_instance PARAMS ((tree, void *));
+static tree dfs_get_pure_virtuals PARAMS ((tree, void *));
/* Allocate a level of searching. */
return stack;
}
\f
-static tree _vptr_name;
-
/* Variables for gathering statistics. */
#ifdef GATHER_STATISTICS
static int n_fields_searched;
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 = -2;
+
+ if (BINFO_TYPE (binfo) == subtype)
+ {
+ if (via_virtual)
+ return -1;
+ 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 == -2)
+ worst = rval;
+ else if (rval >= 0)
+ worst = worst >= 0 ? -3 : worst;
+ else if (rval == -1)
+ worst = -1;
+ else if (rval == -3 && worst != -1)
+ worst = -3;
+ }
+ 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 virtual or non-virtual bases.
+ BOFF == -2, SUBTYPE is not a public base.
+ BOFF == -3, SUBTYPE occurs as multiple public non-virtual bases. */
+
+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'.
of fields!) */
return NULL_TREE;
+ if (TYPE_NAME (type)
+ && DECL_LANG_SPECIFIC (TYPE_NAME (type))
+ && DECL_SORTED_FIELDS (TYPE_NAME (type)))
+ {
+ tree *fields = &TREE_VEC_ELT (DECL_SORTED_FIELDS (TYPE_NAME (type)), 0);
+ int lo = 0, hi = TREE_VEC_LENGTH (DECL_SORTED_FIELDS (TYPE_NAME (type)));
+ int i;
+
+ while (lo < hi)
+ {
+ i = (lo + hi) / 2;
+
+#ifdef GATHER_STATISTICS
+ n_fields_searched++;
+#endif /* GATHER_STATISTICS */
+
+ if (DECL_NAME (fields[i]) > name)
+ hi = i;
+ else if (DECL_NAME (fields[i]) < name)
+ lo = i + 1;
+ else
+ {
+ /* 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;
+ }
+
field = TYPE_FIELDS (type);
#ifdef GATHER_STATISTICS
#endif /* GATHER_STATISTICS */
my_friendly_assert (TREE_CODE_CLASS (TREE_CODE (field)) == 'd', 0);
if (DECL_NAME (field) == NULL_TREE
- && TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
+ && ANON_AGGR_TYPE_P (TREE_TYPE (field)))
{
tree temp = lookup_field_1 (TREE_TYPE (field), name);
if (temp)
field = TREE_CHAIN (field);
}
/* Not found. */
- if (name == _vptr_name)
+ 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;
}
return current_class_type;
if (current_class_type == NULL_TREE)
return current_function_decl;
- if (DECL_CLASS_CONTEXT (current_function_decl) == current_class_type)
+ if ((DECL_FUNCTION_MEMBER_P (current_function_decl)
+ && same_type_p (DECL_CONTEXT (current_function_decl),
+ current_class_type))
+ || (DECL_FRIEND_CONTEXT (current_function_decl)
+ && same_type_p (DECL_FRIEND_CONTEXT (current_function_decl),
+ current_class_type)))
return current_function_decl;
return current_class_type;
}
+/* Returns non-zero if we are currently in a function scope. Note
+ that this function returns zero if we are within a local class, but
+ not within a member function body of the local class. */
+
+int
+at_function_scope_p ()
+{
+ tree cs = current_scope ();
+ return cs && TREE_CODE (cs) == FUNCTION_DECL;
+}
+
/* Return the scope of DECL, as appropriate when doing name-lookup. */
static tree
definition, the members of the anonymous union are considered to
have been defined in the scope in which teh anonymous union is
declared. */
- tree context = DECL_REAL_CONTEXT (decl);
+ tree context = CP_DECL_CONTEXT (decl);
- while (TYPE_P (context) && ANON_UNION_TYPE_P (context))
+ while (TYPE_P (context) && ANON_AGGR_TYPE_P (context))
context = TYPE_CONTEXT (context);
if (!context)
context = global_namespace;
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;
}
+/* Returns non-zero if it is OK to access DECL when named in TYPE
+ through an object indiated by BINFO in the context of DERIVED. */
+
+static int
+protected_accessible_p (type, decl, derived, binfo)
+ tree type;
+ tree decl;
+ tree derived;
+ tree binfo;
+{
+ tree access;
+
+ /* We're checking this clause from [class.access.base]
+
+ m as a member of N is protected, and the reference occurs in a
+ member or friend of class N, or in a member or friend of a
+ class P derived from N, where m as a member of P is private or
+ protected.
+
+ If DERIVED isn't derived from TYPE, then it certainly does not
+ apply. */
+ if (!DERIVED_FROM_P (type, derived))
+ return 0;
+
+ access = access_in_type (derived, decl);
+ if (same_type_p (derived, type))
+ {
+ if (access != access_private_node)
+ return 0;
+ }
+ else if (access != access_private_node
+ && access != access_protected_node)
+ return 0;
+
+ /* [class.protected]
+
+ When a friend or a member function of a derived class references
+ a protected nonstatic member of a base class, an access check
+ applies in addition to those described earlier in clause
+ _class.access_.4) Except when forming a pointer to member
+ (_expr.unary.op_), the access must be through a pointer to,
+ reference to, or object of the derived class itself (or any class
+ derived from that class) (_expr.ref_). If the access is to form
+ a pointer to member, the nested-name-specifier shall name the
+ derived class (or any class derived from that class). */
+ if (DECL_NONSTATIC_MEMBER_P (decl))
+ {
+ /* We can tell through what the reference is occurring by
+ chasing BINFO up to the root. */
+ tree t = binfo;
+ while (BINFO_INHERITANCE_CHAIN (t))
+ t = BINFO_INHERITANCE_CHAIN (t);
+
+ if (!DERIVED_FROM_P (derived, BINFO_TYPE (t)))
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Returns non-zero if SCOPE is a friend of a type which would be able
+ to acces DECL, named in TYPE, through the object indicated by
+ BINFO. */
+
+static int
+friend_accessible_p (scope, type, decl, binfo)
+ tree scope;
+ tree type;
+ tree decl;
+ tree binfo;
+{
+ tree befriending_classes;
+ tree t;
+
+ if (!scope)
+ return 0;
+
+ if (TREE_CODE (scope) == FUNCTION_DECL
+ || DECL_FUNCTION_TEMPLATE_P (scope))
+ befriending_classes = DECL_BEFRIENDING_CLASSES (scope);
+ else if (TYPE_P (scope))
+ befriending_classes = CLASSTYPE_BEFRIENDING_CLASSES (scope);
+ else
+ return 0;
+
+ for (t = befriending_classes; t; t = TREE_CHAIN (t))
+ if (protected_accessible_p (type, decl, TREE_VALUE (t), binfo))
+ return 1;
+
+ /* Nested classes are implicitly friends of their enclosing types, as
+ per core issue 45 (this is a change from the standard). */
+ if (TYPE_P (scope))
+ for (t = TYPE_CONTEXT (scope); t && TYPE_P (t); t = TYPE_CONTEXT (t))
+ if (protected_accessible_p (type, decl, t, binfo))
+ return 1;
+
+ if (TREE_CODE (scope) == FUNCTION_DECL
+ || DECL_FUNCTION_TEMPLATE_P (scope))
+ {
+ /* Perhaps this SCOPE is a member of a class which is a
+ friend. */
+ if (DECL_CLASS_SCOPE_P (decl)
+ && friend_accessible_p (DECL_CONTEXT (scope), type,
+ decl, binfo))
+ return 1;
+
+ /* Or an instantiation of something which is a friend. */
+ if (DECL_TEMPLATE_INFO (scope))
+ return friend_accessible_p (DECL_TI_TEMPLATE (scope),
+ type, decl, binfo);
+ }
+ else if (CLASSTYPE_TEMPLATE_INFO (scope))
+ return friend_accessible_p (CLASSTYPE_TI_TEMPLATE (scope),
+ type, decl, binfo);
+
+ return 0;
+}
+
+/* Perform access control on TYPE_DECL VAL, which was looked up in TYPE.
+ This is fairly complex, so here's the design:
+
+ The lang_extdef nonterminal sets type_lookups to NULL_TREE before we
+ start to process a top-level declaration.
+ As we process the decl-specifier-seq for the declaration, any types we
+ see that might need access control are passed to type_access_control,
+ which defers checking by adding them to type_lookups.
+ When we are done with the decl-specifier-seq, we record the lookups we've
+ seen in the lookups field of the typed_declspecs nonterminal.
+ When we process the first declarator, either in parse_decl or
+ begin_function_definition, we call initial_deferred_type_access_control,
+ which processes any lookups from within that declarator, stores the
+ lookups from the decl-specifier-seq in current_type_lookups, and sets
+ type_lookups to error_mark_node.
+ Subsequent declarators process current_type_lookups again to make sure
+ that the types are accessible to all of the declarators. Any lookups
+ within subsequent declarators are processed immediately.
+ Within a function, type_lookups is error_mark_node, so all lookups are
+ processed immediately. */
+
+void
+type_access_control (type, val)
+ tree type, val;
+{
+ if (val == NULL_TREE || TREE_CODE (val) != TYPE_DECL
+ || ! DECL_CLASS_SCOPE_P (val))
+ return;
+
+ if (type_lookups == error_mark_node)
+ enforce_access (type, val);
+ else if (! accessible_p (type, val))
+ type_lookups = tree_cons (type, val, type_lookups);
+}
+
/* DECL is a declaration from a base class of TYPE, which was the
- classs used to name DECL. Return non-zero if, in the current
+ class used to name DECL. Return non-zero if, in the current
context, DECL is accessible. If TYPE is actually a BINFO node,
then we can tell in what context the access is occurring by looking
at the most derived class along the path indicated by BINFO. */
tree decl;
{
- tree scope;
tree binfo;
tree t;
if (!TYPE_P (context_for_name_lookup (decl)))
return 1;
- /* We don't do access control for types yet. */
- if (TREE_CODE (decl) == TYPE_DECL)
- return 1;
-
if (!TYPE_P (type))
{
binfo = type;
/* Figure out where the reference is occurring. Check to see if
DECL is private or protected in this scope, since that will
determine whether protected access in TYPE allowed. */
- if (current_class_type
- && DERIVED_FROM_P (type, current_class_type))
- {
- tree access = access_in_type (current_class_type, decl);
- if (same_type_p (current_class_type, type)
- && access == access_private_node)
- protected_ok = 1;
- else if (access && (access == access_private_node
- || access == access_protected_node))
- protected_ok = 1;
- }
-
- /* Now, loop through the classes of which SCOPE is a friend. */
- if (!protected_ok && scope)
- {
- /* FIXME: Implement this. Right now, we have no way of knowing
- which classes befriend a particular function or class. */
- }
-
- /* [class.protected]
-
- When a friend or a member function of a derived class references
- a protected nonstatic member of a base class, an access check
- applies in addition to those described earlier in clause
- _class.access_.4) Except when forming a pointer to member
- (_expr.unary.op_), the access must be through a pointer to,
- reference to, or object of the derived class itself (or any class
- derived from that class) (_expr.ref_). If the access is to form
- a pointer to member, the nested-name-specifier shall name the
- derived class (or any class derived from that class). */
- if (protected_ok && DECL_NONSTATIC_MEMBER_P (decl))
- {
- /* We can tell through what the reference is occurring by
- chasing BINFO up to the root. */
- t = binfo;
- while (BINFO_INHERITANCE_CHAIN (t))
- t = BINFO_INHERITANCE_CHAIN (t);
-
- if (!DERIVED_FROM_P (current_class_type, BINFO_TYPE (t)))
- protected_ok = 0;
- }
-
- /* Standardize on the same that will access_in_type will use. We
- don't need to know what path was chosen from this point onwards. */
+ if (current_class_type)
+ protected_ok
+ = protected_accessible_p (type, decl, current_class_type,
+ binfo);
+
+ /* Now, loop through the classes of which we are a friend. */
+ if (!protected_ok)
+ protected_ok = friend_accessible_p (current_scope (),
+ type, decl, binfo);
+
+ /* Standardize the binfo that access_in_type will use. We don't
+ need to know what path was chosen from this point onwards. */
binfo = TYPE_BINFO (type);
/* Compute the accessibility of DECL in the class hierarchy
is_subobject_of_p (parent, binfo)
tree parent, binfo;
{
- tree binfos = BINFO_BASETYPES (binfo);
- int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+ tree binfos;
+ int i, n_baselinks;
- if (TREE_VIA_VIRTUAL (parent))
- parent = TYPE_BINFO (TREE_TYPE (parent));
- if (TREE_VIA_VIRTUAL (binfo))
- binfo = TYPE_BINFO (TREE_TYPE (binfo));
+ /* We want to canonicalize for comparison purposes. But, when we
+ iterate through basetypes later, we want the binfos from the
+ original hierarchy. That's why we have to calculate BINFOS
+ first, and then canonicalize. */
+ binfos = BINFO_BASETYPES (binfo);
+ parent = canonical_binfo (parent);
+ binfo = canonical_binfo (binfo);
if (parent == binfo)
return 1;
+ n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+
/* Process and/or queue base types. */
for (i = 0; i < n_baselinks; i++)
{
- tree base_binfo = canonical_binfo (TREE_VEC_ELT (binfos, i));
+ tree base_binfo = TREE_VEC_ELT (binfos, i);
+ if (!CLASS_TYPE_P (TREE_TYPE (base_binfo)))
+ /* If we see a TEMPLATE_TYPE_PARM, or some such, as a base
+ class there's no way to descend into it. */
+ continue;
+
if (is_subobject_of_p (parent, base_binfo))
return 1;
}
fndecls = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), idx);
while (fndecls)
{
- if (TYPE_MAIN_VARIANT (DECL_CLASS_CONTEXT (OVL_CURRENT (fndecls)))
+ if (TYPE_MAIN_VARIANT (DECL_CONTEXT (OVL_CURRENT (fndecls)))
== TYPE_MAIN_VARIANT (type))
return idx;
fndecls = OVL_CHAIN (fndecls);
/* If non-zero, RVAL was found by looking through a dependent base. */
int from_dep_base_p;
/* If something went wrong, a message indicating what. */
- char *errstr;
+ const char *errstr;
};
/* Returns non-zero if BINFO is not hidden by the value found by the
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;
}
+/* Within the scope of a template class, you can refer to the to the
+ current specialization with the name of the template itself. For
+ example:
+
+ template <typename T> struct S { S* sp; }
+
+ Returns non-zero if DECL is such a declaration in a class TYPE. */
+
+static int
+template_self_reference_p (type, decl)
+ tree type;
+ tree decl;
+{
+ return (CLASSTYPE_USE_TEMPLATE (type)
+ && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (type))
+ && TREE_CODE (decl) == TYPE_DECL
+ && DECL_ARTIFICIAL (decl)
+ && DECL_NAME (decl) == constructor_name (type));
+}
+
/* DATA is really a struct lookup_field_info. Look for a field with
the name indicated there in BINFO. If this function returns a
non-NULL value it is the result of the lookup. Called from
{
struct lookup_field_info *lfi = (struct lookup_field_info *) data;
tree type = BINFO_TYPE (binfo);
- tree nval;
- int idx;
+ tree nval = NULL_TREE;
int from_dep_base_p;
/* First, look for a function. There can't be a function and a data
member with the same name, and if there's a function and a type
with the same name, the type is hidden by the function. */
- idx = lookup_fnfields_here (type, lfi->name);
- if (idx >= 0)
- nval = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), idx);
- else
+ if (!lfi->want_type)
+ {
+ int idx = lookup_fnfields_here (type, lfi->name);
+ if (idx >= 0)
+ nval = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), idx);
+ }
+
+ if (!nval)
/* Look for a data member or type. */
nval = lookup_field_1 (type, lfi->name);
if (!nval)
return NULL_TREE;
+ /* If we're looking up a type (as with an elaborated type specifier)
+ we ignore all non-types we find. */
+ if (lfi->want_type && TREE_CODE (nval) != TYPE_DECL)
+ {
+ nval = purpose_member (lfi->name, CLASSTYPE_TAGS (type));
+ if (nval)
+ nval = TYPE_MAIN_DECL (TREE_VALUE (nval));
+ else
+ return NULL_TREE;
+ }
+
+ /* You must name a template base class with a template-id. */
+ if (!same_type_p (type, lfi->type)
+ && template_self_reference_p (type, nval))
+ return NULL_TREE;
+
from_dep_base_p = dependent_base_p (binfo);
if (lfi->from_dep_base_p && !from_dep_base_p)
{
/* We have a real ambiguity. We keep a chain of all the
candidates. */
if (!lfi->ambiguous && lfi->rval)
- /* 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);
+ {
+ /* This is the first time we noticed an ambiguity. Add
+ what we previously thought was a reasonable candidate
+ to the list. */
+ 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";
}
}
else
{
- /* The new lookup is the best we've got so far. Verify that
- it's the kind of thing we're looking for. */
- if (lfi->want_type && TREE_CODE (nval) != TYPE_DECL)
+ /* If the thing we're looking for is a virtual base class, then
+ we know we've got what we want at this point; there's no way
+ to get an ambiguity. */
+ if (VBASE_NAME_P (lfi->name))
{
- nval = purpose_member (lfi->name, CLASSTYPE_TAGS (type));
- if (nval)
- nval = TYPE_MAIN_DECL (TREE_VALUE (nval));
+ lfi->rval = nval;
+ return nval;
}
- if (nval)
- {
- /* If the thing we're looking for is a virtual base class,
- then we know we've got what we want at this point;
- there's no way to get an ambiguity. */
- if (VBASE_NAME_P (lfi->name))
- {
- lfi->rval = nval;
- return nval;
- }
-
- if (from_dep_base_p && TREE_CODE (nval) != TYPE_DECL
- /* We need to return a member template class so we can
- define partial specializations. Is there a better
- way? */
- && !DECL_CLASS_TEMPLATE_P (nval))
- /* The thing we're looking for isn't a type, so the implicit
- typename extension doesn't apply, so we just pretend we
- didn't find anything. */
- return NULL_TREE;
- }
+ if (from_dep_base_p && TREE_CODE (nval) != TYPE_DECL
+ /* We need to return a member template class so we can
+ define partial specializations. Is there a better
+ way? */
+ && !DECL_CLASS_TEMPLATE_P (nval))
+ /* The thing we're looking for isn't a type, so the implicit
+ typename extension doesn't apply, so we just pretend we
+ didn't find anything. */
+ return NULL_TREE;
lfi->rval = nval;
lfi->from_dep_base_p = from_dep_base_p;
}
/* Look for a memer named NAME in an inheritance lattice dominated by
- XBASETYPE. PROTECT is zero if we can avoid computing access
- information, otherwise it is 1. WANT_TYPE is 1 when we should only
- return TYPE_DECLs, if no TYPE_DECL can be found return NULL_TREE.
+ XBASETYPE. PROTECT is 0 or two, we do not check access. If it is
+ 1, we enforce accessibility. If PROTECT is zero, then, for an
+ ambiguous lookup, we return NULL. If PROTECT is 1, we issue an
+ error message. If PROTECT is 2, we return a TREE_LIST whose
+ TREE_TYPE is error_mark_node and whose TREE_VALUEs are the list of
+ ambiguous candidates.
- It was not clear what should happen if WANT_TYPE is set, and an
- ambiguity is found. At least one use (lookup_name) to not see
- the error. */
+ WANT_TYPE is 1 when we should only return TYPE_DECLs, if no
+ TYPE_DECL can be found return NULL_TREE. */
tree
lookup_member (xbasetype, name, protect, want_type)
checks. Whereas rval is only set if a proper (not hidden)
non-function member is found. */
- /* rval_binfo_h and binfo_h are binfo values used when we perform the
- hiding checks, as virtual base classes may not be shared. The strategy
- is we always go into the binfo hierarchy owned by TYPE_BINFO of
- virtual base classes, as we cross virtual base class lines. This way
- we know that binfo of a virtual base class will always == itself when
- found along any line. (mrs) */
-
- char *errstr = 0;
+ const char *errstr = 0;
if (xbasetype == current_class_type && TYPE_BEING_DEFINED (xbasetype)
&& IDENTIFIER_CLASS_VALUE (name))
tree field = IDENTIFIER_CLASS_VALUE (name);
if (TREE_CODE (field) != FUNCTION_DECL
&& ! (want_type && TREE_CODE (field) != TYPE_DECL))
+ /* We're in the scope of this class, and the value has already
+ been looked up. Just return the cached value. */
return field;
}
n_calls_lookup_field++;
#endif /* GATHER_STATISTICS */
- bzero (&lfi, sizeof (lfi));
+ bzero ((PTR) &lfi, sizeof (lfi));
lfi.type = type;
lfi.name = name;
lfi.want_type = want_type;
if (!protect && lfi.ambiguous)
return NULL_TREE;
+ if (protect == 2)
+ {
+ if (lfi.ambiguous)
+ return lfi.ambiguous;
+ else
+ protect = 0;
+ }
+
/* [class.access]
In the case of overloaded function names, access control is
applied to the function selected by overloaded resolution. */
if (rval && protect && !is_overloaded_fn (rval)
- && !IS_SIGNATURE_POINTER (DECL_REAL_CONTEXT (rval))
- && !IS_SIGNATURE_REFERENCE (DECL_REAL_CONTEXT (rval))
&& !enforce_access (xbasetype, rval))
return error_mark_node;
name, name,
TREE_TYPE (rval)));
- if (rval && is_overloaded_fn (rval))
- rval = scratch_tree_cons (basetype_path, rval, NULL_TREE);
+ if (rval && is_overloaded_fn (rval))
+ {
+ rval = tree_cons (basetype_path, rval, NULL_TREE);
+ SET_BASELINK_P (rval);
+ }
return rval;
}
return rval;
}
-/* Try to find NAME inside a nested class. */
-
-tree
-lookup_nested_field (name, complain)
- tree name;
- int complain;
-{
- register tree t;
-
- tree id = NULL_TREE;
- if (TYPE_MAIN_DECL (current_class_type))
- {
- /* Climb our way up the nested ladder, seeing if we're trying to
- modify a field in an enclosing class. If so, we should only
- be able to modify if it's static. */
- for (t = TYPE_MAIN_DECL (current_class_type);
- t && DECL_CONTEXT (t);
- t = TYPE_MAIN_DECL (DECL_CONTEXT (t)))
- {
- if (TREE_CODE (DECL_CONTEXT (t)) != RECORD_TYPE)
- break;
-
- /* N.B.: lookup_field will do the access checking for us */
- id = lookup_field (DECL_CONTEXT (t), name, complain, 0);
- if (id == error_mark_node)
- {
- id = NULL_TREE;
- continue;
- }
-
- if (id != NULL_TREE)
- {
- if (TREE_CODE (id) == FIELD_DECL
- && ! TREE_STATIC (id)
- && TREE_TYPE (id) != error_mark_node)
- {
- if (complain)
- {
- /* At parse time, we don't want to give this error, since
- we won't have enough state to make this kind of
- decision properly. But there are times (e.g., with
- enums in nested classes) when we do need to call
- this fn at parse time. So, in those cases, we pass
- complain as a 0 and just return a NULL_TREE. */
- cp_error ("assignment to non-static member `%D' of enclosing class `%T'",
- id, DECL_CONTEXT (t));
- /* Mark this for do_identifier(). It would otherwise
- claim that the variable was undeclared. */
- TREE_TYPE (id) = error_mark_node;
- }
- else
- {
- id = NULL_TREE;
- continue;
- }
- }
- break;
- }
- }
- }
-
- return id;
-}
-
/* TYPE is a class type. Return the index of the fields within
the method vector with name NAME, or -1 is no such field exists. */
lookup_fnfields_1 (type, name)
tree type, name;
{
- register tree method_vec
+ tree method_vec
= CLASS_TYPE_P (type) ? CLASSTYPE_METHOD_VEC (type) : NULL_TREE;
if (method_vec != 0)
{
+ register int i;
register tree *methods = &TREE_VEC_ELT (method_vec, 0);
- register tree *end = TREE_VEC_END (method_vec);
+ int len = TREE_VEC_LENGTH (method_vec);
+ tree tmp;
#ifdef GATHER_STATISTICS
n_calls_lookup_fnfields_1++;
#endif /* GATHER_STATISTICS */
/* Constructors are first... */
- if (*methods && name == ctor_identifier)
- return 0;
+ if (name == ctor_identifier)
+ return methods[0] ? 0 : -1;
/* and destructors are second. */
- if (*++methods && name == dtor_identifier)
- return 1;
+ if (name == dtor_identifier)
+ return methods[1] ? 1 : -1;
- while (++methods != end && *methods)
+ for (i = 2; i < len && methods[i]; ++i)
{
#ifdef GATHER_STATISTICS
n_outer_fields_searched++;
#endif /* GATHER_STATISTICS */
- if (DECL_NAME (OVL_CURRENT (*methods)) == name)
- break;
+
+ tmp = OVL_CURRENT (methods[i]);
+ if (DECL_NAME (tmp) == name)
+ return i;
+
+ /* If the type is complete and we're past the conversion ops,
+ switch to binary search. */
+ if (! DECL_CONV_FN_P (tmp)
+ && TYPE_SIZE (type))
+ {
+ int lo = i + 1, hi = len;
+
+ while (lo < hi)
+ {
+ i = (lo + hi) / 2;
+
+#ifdef GATHER_STATISTICS
+ n_outer_fields_searched++;
+#endif /* GATHER_STATISTICS */
+
+ tmp = DECL_NAME (OVL_CURRENT (methods[i]));
+
+ if (tmp > name)
+ hi = i;
+ else if (tmp < name)
+ lo = i + 1;
+ else
+ return i;
+ }
+ break;
+ }
}
/* If we didn't find it, it might have been a template
conversion operator. (Note that we don't look for this case
above so that we will always find specializations first.) */
- if ((methods == end || !*methods)
- && IDENTIFIER_TYPENAME_P (name))
+ if (IDENTIFIER_TYPENAME_P (name))
{
- methods = &TREE_VEC_ELT (method_vec, 0) + 1;
-
- while (++methods != end && *methods)
+ for (i = 2; i < len && methods[i]; ++i)
{
- tree method_name = DECL_NAME (OVL_CURRENT (*methods));
-
- if (!IDENTIFIER_TYPENAME_P (method_name))
+ tmp = OVL_CURRENT (methods[i]);
+ if (! DECL_CONV_FN_P (tmp))
{
/* Since all conversion operators come first, we know
there is no such operator. */
- methods = end;
break;
}
- else if (TREE_CODE (OVL_CURRENT (*methods)) == TEMPLATE_DECL)
- break;
+ else if (TREE_CODE (tmp) == TEMPLATE_DECL)
+ return i;
}
}
-
- if (methods != end && *methods)
- return methods - &TREE_VEC_ELT (method_vec, 0);
}
return -1;
static tree
bfs_walk (binfo, fn, qfn, data)
tree binfo;
- tree (*fn) PROTO((tree, void *));
- tree (*qfn) PROTO((tree, void *));
+ tree (*fn) PARAMS ((tree, void *));
+ tree (*qfn) PARAMS ((tree, void *));
void *data;
{
size_t head;
performed, and PREFN is called in preorder, while POSTFN is called
in postorder. */
-static tree
+tree
dfs_walk_real (binfo, prefn, postfn, qfn, data)
tree binfo;
- tree (*prefn) PROTO((tree, void *));
- tree (*postfn) PROTO((tree, void *));
- tree (*qfn) PROTO((tree, void *));
+ tree (*prefn) PARAMS ((tree, void *));
+ tree (*postfn) PARAMS ((tree, void *));
+ tree (*qfn) PARAMS ((tree, void *));
void *data;
{
int i;
tree
dfs_walk (binfo, fn, qfn, data)
tree binfo;
- tree (*fn) PROTO((tree, void *));
- tree (*qfn) PROTO((tree, void *));
+ tree (*fn) PARAMS ((tree, void *));
+ tree (*qfn) PARAMS ((tree, void *));
void *data;
{
return dfs_walk_real (binfo, 0, fn, qfn, data);
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 1;
}
-/* Given a class type TYPE, and a function decl FNDECL, look for a
- virtual function in TYPE's hierarchy which FNDECL could match as a
- virtual function. It doesn't matter which one we find.
+/* Check that virtual overrider OVERRIDER is acceptable for base function
+ BASEFN. Issue diagnostic, and return zero, if unacceptable. */
- DTORP is nonzero if we are looking for a destructor. Destructors
- need special treatment because they do not match by name. */
+static int
+check_final_overrider (overrider, basefn)
+ tree overrider, basefn;
+{
+ tree over_type = TREE_TYPE (overrider);
+ tree base_type = TREE_TYPE (basefn);
+ tree over_return = TREE_TYPE (over_type);
+ tree base_return = TREE_TYPE (base_type);
+ tree over_throw = TYPE_RAISES_EXCEPTIONS (over_type);
+ tree base_throw = TYPE_RAISES_EXCEPTIONS (base_type);
+ int i;
+
+ if (same_type_p (base_return, over_return))
+ /* OK */;
+ else if ((i = covariant_return_p (base_return, over_return)))
+ {
+ if (i == 2)
+ sorry ("adjusting pointers for covariant returns");
-tree
-get_matching_virtual (binfo, fndecl, dtorp)
+ if (pedantic && i == -1)
+ {
+ cp_pedwarn_at ("invalid covariant return type for `virtual %#D'", overrider);
+ cp_pedwarn_at (" overriding `virtual %#D' (must be pointer or reference to class)", basefn);
+ }
+ }
+ else if (IS_AGGR_TYPE_2 (base_return, over_return)
+ && same_or_base_type_p (base_return, over_return))
+ {
+ cp_error_at ("invalid covariant return type for `virtual %#D'", overrider);
+ cp_error_at (" overriding `virtual %#D' (must use pointer or reference)", basefn);
+ return 0;
+ }
+ else if (IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (overrider)) == NULL_TREE)
+ {
+ cp_error_at ("conflicting return type specified for `virtual %#D'", overrider);
+ cp_error_at (" overriding `virtual %#D'", basefn);
+ SET_IDENTIFIER_ERROR_LOCUS (DECL_ASSEMBLER_NAME (overrider),
+ DECL_CONTEXT (overrider));
+ return 0;
+ }
+
+ /* Check throw specifier is subset. */
+ /* XXX At the moment, punt on an overriding artificial function. We
+ don't generate its exception specifier, so can't check it properly. */
+ if (! DECL_ARTIFICIAL (overrider)
+ && !comp_except_specs (base_throw, over_throw, 0))
+ {
+ cp_error_at ("looser throw specifier for `virtual %#F'", overrider);
+ cp_error_at (" overriding `virtual %#F'", basefn);
+ return 0;
+ }
+ return 1;
+}
+
+/* Given a class type TYPE, and a function decl FNDECL, look for a
+ virtual function in TYPE's hierarchy which FNDECL could match as a
+ virtual function. It doesn't matter which one we find.
+
+ DTORP is nonzero if we are looking for a destructor. Destructors
+ need special treatment because they do not match by name. */
+
+tree
+get_matching_virtual (binfo, fndecl, dtorp)
tree binfo, fndecl;
int dtorp;
{
tree tmp = NULL_TREE;
- int i;
if (TREE_CODE (fndecl) == TEMPLATE_DECL)
/* In [temp.mem] we have:
else
{
tree drettype, dtypes, btypes, instptr_type;
- tree basetype = DECL_CLASS_CONTEXT (fndecl);
tree baselink, best = NULL_TREE;
- tree name = DECL_ASSEMBLER_NAME (fndecl);
tree declarator = DECL_NAME (fndecl);
if (IDENTIFIER_VIRTUAL_P (declarator) == 0)
return NULL_TREE;
== TYPE_QUALS (instptr_type))
&& compparms (TREE_CHAIN (btypes), TREE_CHAIN (dtypes)))
{
- tree brettype = TREE_TYPE (TREE_TYPE (tmp));
- if (same_type_p (brettype, drettype))
- /* OK */;
- else if ((i = covariant_return_p (brettype, drettype)))
- {
- if (i == 2)
- sorry ("adjusting pointers for covariant returns");
-
- if (pedantic && i == -1)
- {
- cp_pedwarn_at ("invalid covariant return type for `%#D' (must be pointer or reference to class)", fndecl);
- cp_pedwarn_at (" overriding `%#D'", tmp);
- }
- }
- else if (IS_AGGR_TYPE_2 (brettype, drettype)
- && same_or_base_type_p (brettype, drettype))
- {
- error ("invalid covariant return type (must use pointer or reference)");
- cp_error_at (" overriding `%#D'", tmp);
- cp_error_at (" with `%#D'", fndecl);
- }
- else if (IDENTIFIER_ERROR_LOCUS (name) == NULL_TREE)
- {
- cp_error_at ("conflicting return type specified for virtual function `%#D'", fndecl);
- cp_error_at (" overriding definition as `%#D'", tmp);
- SET_IDENTIFIER_ERROR_LOCUS (name, basetype);
- }
+ check_final_overrider (fndecl, tmp);
/* FNDECL overrides this function. We continue to
check all the other functions in order to catch
}
}
-/* 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);
+ 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_pfn = FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (virtuals));
- tree base_fndecl = TREE_OPERAND (base_pfn, 0);
- 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;
}
-/* 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. */
+/* Set BINFO_PRIMARY_MARKED_P for all binfos in the hierarchy
+ dominated by BINFO that are primary bases. */
-tree
-get_abstract_virtuals (type)
+void
+mark_primary_bases (type)
tree type;
{
- tree vbases;
- tree abstract_virtuals = NULL;
+ tree vbase;
+
+ /* Mark the TYPE_BINFO hierarchy. We need to mark primary bases in
+ pre-order to deal with primary virtual bases. (The virtual base
+ would be skipped if it were not marked as primary, and that
+ requires getting to dfs_mark_primary_bases before
+ dfs_skip_nonprimary_vbases_unmarkedp has a chance to skip the
+ virtual base.) */
+ dfs_walk_real (TYPE_BINFO (type), dfs_mark_primary_bases, NULL,
+ 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);
+}
- /* 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 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, data)
+ tree binfo;
+ void *data;
+{
+ if (TREE_VIA_VIRTUAL (binfo) && !BINFO_PRIMARY_MARKED_P (binfo))
{
- tree virtuals = BINFO_VIRTUALS (vbases);
+ tree type = (tree) data;
- skip_rtti_stuff (&virtuals);
+ if (TREE_CODE (type) == TREE_LIST)
+ type = TREE_PURPOSE (type);
- while (virtuals)
- {
- tree base_pfn = FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (virtuals));
- tree base_fndecl = TREE_OPERAND (base_pfn, 0);
- 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);
- }
+ /* 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 nreverse (abstract_virtuals);
+
+ return binfo;
}
-/* For the type TYPE, return a list of member functions available from
- base classes with name NAME. The TREE_VALUE of the list is a chain of
- member functions with name NAME. The TREE_PURPOSE of the list is a
- basetype, or a list of base types (in reverse order) which were
- traversed to reach the chain of member functions. If we reach a base
- type which provides a member function of name NAME, and which has at
- most one base type itself, then we can terminate the search. */
+/* 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_baselinks (type_as_binfo_list, type, name)
- tree type_as_binfo_list;
- tree type, name;
+dfs_unmarked_real_bases_queue_p (binfo, data)
+ tree binfo;
+ void *data;
{
- int head = 0, tail = 0, idx;
- tree rval = 0, nval = 0;
- tree basetypes = type_as_binfo_list;
- tree binfo = TYPE_BINFO (type);
+ binfo = get_shared_vbase_if_not_primary (binfo, data);
+ return binfo ? unmarkedp (binfo, NULL) : NULL_TREE;
+}
- search_stack = push_search_level (search_stack, &search_obstack);
+/* Like dfs_unmarked_real_bases_queue_p but walks only into things
+ that are marked, rather than unmarked. */
- while (1)
+tree
+dfs_marked_real_bases_queue_p (binfo, data)
+ tree binfo;
+ void *data;
+{
+ binfo = get_shared_vbase_if_not_primary (binfo, data);
+ return binfo ? markedp (binfo, NULL) : NULL_TREE;
+}
+
+/* Like dfs_unmarked_real_bases_queue_p but walks only into things
+ that are not BINFO_VTABLE_PATH_MARKED. */
+
+tree
+dfs_vtable_path_unmarked_real_bases_queue_p (binfo, data)
+ tree binfo;
+ void *data;
+{
+ binfo = get_shared_vbase_if_not_primary (binfo, data);
+ return binfo ? unmarked_vtable_pathp (binfo, NULL): NULL_TREE;
+}
+
+/* Like dfs_unmarked_real_bases_queue_p but walks only into things
+ that are BINFO_VTABLE_PATH_MARKED. */
+
+tree
+dfs_vtable_path_marked_real_bases_queue_p (binfo, data)
+ tree binfo;
+ void *data;
+{
+ binfo = get_shared_vbase_if_not_primary (binfo, data);
+ return binfo ? marked_vtable_pathp (binfo, NULL): NULL_TREE;
+}
+
+/* A queue function that skips all virtual bases (and their
+ bases). */
+
+tree
+dfs_skip_vbases (binfo, data)
+ tree binfo;
+ void *data ATTRIBUTE_UNUSED;
+{
+ if (TREE_VIA_VIRTUAL (binfo))
+ return NULL_TREE;
+
+ return binfo;
+}
+
+/* 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 binfos = BINFO_BASETYPES (binfo);
- int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+ 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);
- /* Process and/or queue base types. */
- for (i = 0; i < n_baselinks; i++)
- {
- tree base_binfo = TREE_VEC_ELT (binfos, i);
- tree btypes;
-
- btypes = hash_tree_cons (TREE_VIA_PUBLIC (base_binfo),
- TREE_VIA_VIRTUAL (base_binfo),
- TREE_VIA_PROTECTED (base_binfo),
- NULL_TREE, base_binfo,
- basetypes);
- obstack_ptr_grow (&search_obstack, btypes);
- search_stack->first = (tree *)obstack_base (&search_obstack);
- tail += 1;
- }
+ return NULL_TREE;
+}
- dont_queue:
- /* Process head of queue, if one exists. */
- if (head >= tail)
- break;
+/* Set CLASSTYPE_PURE_VIRTUALS for TYPE. */
- basetypes = search_stack->first[head++];
- binfo = TREE_VALUE (basetypes);
- type = BINFO_TYPE (binfo);
- idx = lookup_fnfields_1 (type, name);
- if (idx >= 0)
+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))
{
- nval = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), idx);
- rval = hash_tree_cons (0, 0, 0, basetypes, nval, rval);
- if (TYPE_BINFO_BASETYPES (type) == 0)
- goto dont_queue;
- else if (TREE_VEC_LENGTH (TYPE_BINFO_BASETYPES (type)) == 1)
- {
- if (CLASSTYPE_BASELINK_VEC (type))
- TREE_TYPE (rval) = TREE_VEC_ELT (CLASSTYPE_BASELINK_VEC (type), idx);
- goto dont_queue;
- }
+ tree base_fndecl = TREE_VALUE (virtuals);
+ if (DECL_NEEDS_FINAL_OVERRIDER_P (base_fndecl))
+ cp_error ("`%#D' needs a final overrider", base_fndecl);
}
- nval = NULL_TREE;
}
-
- search_stack = pop_search_level (search_stack);
- return rval;
}
-tree
+static tree
next_baselink (baselink)
tree baselink;
{
convert_pointer_to_single_level (to_type, expr)
tree to_type, expr;
{
+ tree derived;
tree binfo_of_derived;
- tree last;
+ int i;
- binfo_of_derived = TYPE_BINFO (TREE_TYPE (TREE_TYPE (expr)));
- last = get_binfo (to_type, TREE_TYPE (TREE_TYPE (expr)), 0);
- my_friendly_assert (BINFO_INHERITANCE_CHAIN (last) == binfo_of_derived,
- 980827);
+ derived = TREE_TYPE (TREE_TYPE (expr));
+ binfo_of_derived = TYPE_BINFO (derived);
my_friendly_assert (BINFO_INHERITANCE_CHAIN (binfo_of_derived) == NULL_TREE,
980827);
- return build_vbase_path (PLUS_EXPR, build_pointer_type (to_type), expr,
- last, 1);
-}
-
-/* Like dfs_walk, but only walk until fn returns something, and return
- that. We also use the real vbase binfos instead of the placeholders
- in the normal binfo hierarchy. START is the most-derived type for this
- hierarchy, so that we can find the vbase binfos. */
-
-static tree
-dfs_search (binfo, fn, start)
- tree binfo, start;
- tree (*fn) PROTO((tree));
-{
- tree binfos = BINFO_BASETYPES (binfo);
- int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
- tree retval;
-
- for (i = 0; i < n_baselinks; i++)
+ for (i = CLASSTYPE_N_BASECLASSES (derived) - 1; i >= 0; --i)
{
- tree base_binfo = TREE_VEC_ELT (binfos, i);
-
- if (TREE_CODE (BINFO_TYPE (base_binfo)) == TEMPLATE_TYPE_PARM
- || TREE_CODE (BINFO_TYPE (base_binfo)) == TEMPLATE_TEMPLATE_PARM)
- /* Pass */;
- else
- {
- if (TREE_VIA_VIRTUAL (base_binfo) && start)
- base_binfo = binfo_member (BINFO_TYPE (base_binfo),
- CLASSTYPE_VBASECLASSES (start));
- retval = dfs_search (base_binfo, fn, start);
- if (retval)
- return retval;
- }
+ tree binfo = BINFO_BASETYPE (binfo_of_derived, i);
+ my_friendly_assert (BINFO_INHERITANCE_CHAIN (binfo) == binfo_of_derived,
+ 980827);
+ if (same_type_p (BINFO_TYPE (binfo), to_type))
+ return build_vbase_path (PLUS_EXPR,
+ build_pointer_type (to_type),
+ expr, binfo, 1);
}
- return fn (binfo);
+ my_friendly_abort (19990607);
+
+ /* NOTREACHED */
+ 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;
tree binfo;
void *data ATTRIBUTE_UNUSED;
{
- return BINFO_PUSHDECLS_MARKED (binfo) ? binfo : NULL_TREE;
+ return (CLASS_TYPE_P (BINFO_TYPE (binfo))
+ && BINFO_PUSHDECLS_MARKED (binfo)) ? binfo : NULL_TREE;
}
static tree
tree binfo;
void *data ATTRIBUTE_UNUSED;
{
- return !BINFO_PUSHDECLS_MARKED (binfo) ? binfo : NULL_TREE;
+ return (CLASS_TYPE_P (BINFO_TYPE (binfo))
+ && !BINFO_PUSHDECLS_MARKED (binfo)) ? binfo : NULL_TREE;
}
#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);
+}
+
+/* Clear BINFO_VTABLE_PATH_MARKED. */
+
+tree
+dfs_vtable_path_unmark (binfo, data)
+ tree binfo;
+ void *data ATTRIBUTE_UNUSED;
+{
+ CLEAR_BINFO_VTABLE_PATH_MARKED (binfo);
+ return NULL_TREE;
+}
+
#if 0
static void
dfs_mark_vtable_path (binfo) tree binfo;
{ SET_BINFO_VTABLE_PATH_MARKED (binfo); }
static void
-dfs_unmark_vtable_path (binfo) tree binfo;
-{ CLEAR_BINFO_VTABLE_PATH_MARKED (binfo); }
-
-static void
dfs_mark_new_vtable (binfo) tree binfo;
{ SET_BINFO_NEW_VTABLE_MARKED (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)))
}
/* get the virtual context (the vbase that directly contains the
- DECL_CLASS_CONTEXT of the FNDECL) that the given FNDECL is declared in,
+ DECL_CONTEXT of the FNDECL) that the given FNDECL is declared in,
or NULL_TREE if there is none.
- FNDECL must come from a virtual table from a virtual base to ensure that
- there is only one possible DECL_CLASS_CONTEXT.
+ FNDECL must come from a virtual table from a virtual base to ensure
+ that there is only one possible DECL_CONTEXT.
We know that if there is more than one place (binfo) the fndecl that the
declared, they all refer to the same binfo. See get_class_offset_1 for
tree fndecl, t, vbase;
{
tree path;
- if (get_base_distance (DECL_CLASS_CONTEXT (fndecl), t, 0, &path) < 0)
+ if (get_base_distance (DECL_CONTEXT (fndecl), t, 0, &path) < 0)
{
- /* DECL_CLASS_CONTEXT can be ambiguous in t. */
- if (get_base_distance (DECL_CLASS_CONTEXT (fndecl), vbase, 0, &path) >= 0)
+ /* DECL_CONTEXT can be ambiguous in t. */
+ if (get_base_distance (DECL_CONTEXT (fndecl), vbase, 0, &path) >= 0)
{
while (path)
{
/* 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;
-
+
+ while (BINFO_PRIMARY_MARKED_P (binfo))
+ {
+ binfo = BINFO_INHERITANCE_CHAIN (binfo);
+ if (TREE_VIA_VIRTUAL (binfo))
+ return;
+ }
+
delta = purpose_member (vbase, *vbase_offsets);
if (! delta)
{
*vbase_offsets = delta;
}
- n = skip_rtti_stuff (&virtuals);
+ virtuals = skip_rtti_stuff (binfo, BINFO_TYPE (binfo), &n);
while (virtuals)
{
tree current_fndecl = TREE_VALUE (virtuals);
- current_fndecl = FNADDR_FROM_VTABLE_ENTRY (current_fndecl);
- current_fndecl = TREE_OPERAND (current_fndecl, 0);
+
if (current_fndecl
&& current_fndecl != abort_fndecl
&& (vc=virtual_context (current_fndecl, t, vbase)) != vbase)
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);
/* This is a upcast, so we have to add the offset for the
virtual base. */
old_delta = build_binary_op (PLUS_EXPR, old_delta,
- TREE_VALUE (delta), 0);
+ TREE_VALUE (delta));
if (vc)
{
/* If this is set, we need to subtract out the delta
/* This is a downcast, so we have to subtract the offset
for the virtual base. */
- old_delta = build_binary_op (MINUS_EXPR, old_delta, vc_delta, 0);
+ old_delta = build_binary_op (MINUS_EXPR, old_delta, vc_delta);
}
TREE_READONLY (new_delta) = 0;
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;
tree real_base_binfo = TREE_VEC_ELT (real_binfos, i);
tree base_binfo = TREE_VEC_ELT (binfos, i);
int is_not_base_vtable
- = i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (real_binfo));
+ = !BINFO_PRIMARY_MARKED_P (real_base_binfo);
if (! TREE_VIA_VIRTUAL (real_base_binfo))
fixup_virtual_upcast_offsets (real_base_binfo, base_binfo,
is_not_base_vtable, can_elide, addr,
}
}
-/* 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;
+ tree vbase_offsets;
+ tree addr;
+
+ vbase = find_vbase_instance (BINFO_TYPE (vbases), type);
+ vbase_offsets = NULL_TREE;
+ addr = convert_pointer_to_vbase (BINFO_TYPE (vbases), decl_ptr);
+ fixup_virtual_upcast_offsets (vbase,
+ TYPE_BINFO (BINFO_TYPE (vbases)),
+ 1, 0, addr, decl_ptr,
+ type, vbase, &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)
- {
- extern tree in_charge_identifier;
- 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, 1);
- 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);
+}
+
+/* Called from find_vbase_instance via dfs_walk. */
+
+static tree
+dfs_find_vbase_instance (binfo, data)
+ tree binfo;
+ void *data;
+{
+ tree base = TREE_VALUE ((tree) data);
+
+ if (BINFO_PRIMARY_MARKED_P (binfo)
+ && same_type_p (BINFO_TYPE (binfo), base))
+ return binfo;
+
+ return NULL_TREE;
+}
- /* unmark marked vbases */
- for (vbases = vbase_types; vbases; vbases = TREE_CHAIN (vbases))
- CLEAR_BINFO_VBASE_MARKED (vbases);
+/* Find the real occurrence of the virtual BASE (a class type) in the
+ hierarchy dominated by TYPE. */
- return vbase_types;
+tree
+find_vbase_instance (base, type)
+ tree base;
+ tree type;
+{
+ tree instance;
+
+ instance = BINFO_FOR_VBASE (base, type);
+ if (!BINFO_VBASE_PRIMARY_P (instance))
+ return instance;
+
+ return dfs_walk (TYPE_BINFO (type),
+ dfs_find_vbase_instance,
+ NULL,
+ build_tree_list (type, base));
}
+
\f
+/* Debug info for C++ classes can get very large; try to avoid
+ emitting it everywhere.
+
+ Note that this optimization wins even when the target supports
+ BINCL (if only slightly), and reduces the amount of work for the
+ linker. */
+
+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 a vtable, write out the debug info along with
+ the vtable. */
+ else if (TYPE_CONTAINS_VPTR_P (t))
+ TYPE_DECL_SUPPRESS_DEBUG (TYPE_MAIN_DECL (t)) = 1;
+
+ /* Otherwise, just emit the debug info normally. */
+}
+
+#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)
+ /* 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 (). */
-/* Add in a decl to the envelope. */
-static void
-envelope_add_decl (type, decl, values)
- tree type, decl, *values;
-{
- tree context, *tmp;
- tree name = DECL_NAME (decl);
- int dont_add = 0;
-
- /* Yet Another Implicit Typename Kludge: Since we don't tsubst
- the members for partial instantiations, DECL_CONTEXT (decl) is wrong.
- But pretend it's right for this function. */
- if (processing_template_decl)
- type = DECL_REAL_CONTEXT (decl);
-
- /* virtual base names are always unique. */
- if (VBASE_NAME_P (name))
- *values = NULL_TREE;
-
- /* Possible ambiguity. If its defining type(s)
- is (are all) derived from us, no problem. */
- else if (*values && TREE_CODE (*values) != TREE_LIST)
- {
- tree value = *values;
- /* Only complain if we shadow something we can access. */
- if (warn_shadow && TREE_CODE (decl) == FUNCTION_DECL
- && ((DECL_LANG_SPECIFIC (*values)
- && DECL_CLASS_CONTEXT (value) == current_class_type)
- || ! TREE_PRIVATE (value)))
- /* Should figure out access control more accurately. */
- {
- cp_warning_at ("member `%#D' is shadowed", value);
- cp_warning_at ("by member function `%#D'", decl);
- warning ("in this context");
- }
-
- context = DECL_REAL_CONTEXT (value);
-
- if (context == type)
- {
- if (TREE_CODE (value) == TYPE_DECL
- && DECL_ARTIFICIAL (value))
- *values = NULL_TREE;
- else
- dont_add = 1;
- }
- else if (type == current_class_type
- || DERIVED_FROM_P (context, type))
- {
- /* Don't add in *values to list */
- *values = NULL_TREE;
- }
- else
- *values = build_tree_list (NULL_TREE, value);
- }
- else
- for (tmp = values; *tmp;)
- {
- tree value = TREE_VALUE (*tmp);
- my_friendly_assert (TREE_CODE (value) != TREE_LIST, 999);
- context = (TREE_CODE (value) == FUNCTION_DECL
- && DECL_VIRTUAL_P (value))
- ? DECL_CLASS_CONTEXT (value)
- : DECL_CONTEXT (value);
-
- if (type == current_class_type
- || DERIVED_FROM_P (context, type))
- {
- /* remove *tmp from list */
- *tmp = TREE_CHAIN (*tmp);
- }
- else
- tmp = &TREE_CHAIN (*tmp);
- }
-
- if (! dont_add)
- {
- /* Put the new contents in our envelope. */
- if (TREE_CODE (decl) == FUNCTION_DECL)
- {
- *values = tree_cons (name, decl, *values);
- TREE_NONLOCAL_FLAG (*values) = 1;
- TREE_TYPE (*values) = unknown_type_node;
- }
- else
- {
- if (*values)
- {
- *values = tree_cons (NULL_TREE, decl, *values);
- /* Mark this as a potentially ambiguous member. */
- /* Leaving TREE_TYPE blank is intentional.
- We cannot use `error_mark_node' (lookup_name)
- or `unknown_type_node' (all member functions use this). */
- TREE_NONLOCAL_FLAG (*values) = 1;
- }
- else
- *values = decl;
- }
- }
-}
-
/* Returns 1 iff BINFO is a base we shouldn't really be able to see into,
because it (or one of the intermediate bases) depends on template parms. */
return 0;
}
-/* Add the instance variables which this class contributed to the
- current class binding contour. When a redefinition occurs, if the
- redefinition is strictly within a single inheritance path, we just
- overwrite the old declaration with the new. If the fields are not
- within a single inheritance path, we must cons them.
-
- In order to know what decls are new (stemming from the current
- invocation of push_class_decls) we enclose them in an "envelope",
- which is a TREE_LIST node where the TREE_PURPOSE slot contains the
- new decl (or possibly a list of competing ones), the TREE_VALUE slot
- points to the old value and the TREE_CHAIN slot chains together all
- envelopes which needs to be "opened" in push_class_decls. Opening an
- envelope means: push the old value onto the class_shadowed list,
- install the new one and if it's a TYPE_DECL do the same to the
- IDENTIFIER_TYPE_VALUE. Such an envelope is recognized by seeing that
- the TREE_PURPOSE slot is non-null, and that it is not an identifier.
- Because if it is, it could be a set of overloaded methods from an
- outer scope. */
-
-static tree
-dfs_pushdecls (binfo, data)
- tree binfo;
- void *data;
+static void
+setup_class_bindings (name, type_binding_p)
+ tree name;
+ int type_binding_p;
{
- tree *closed_envelopes = (tree *) data;
- tree type = BINFO_TYPE (binfo);
- tree fields;
- tree method_vec;
- int dummy = 0;
+ tree type_binding = NULL_TREE;
+ tree value_binding;
- /* Only record types if we're a template base. */
- if (processing_template_decl && type != current_class_type
- && dependent_base_p (binfo))
- dummy = 1;
+ /* If we've already done the lookup for this declaration, we're
+ done. */
+ if (IDENTIFIER_CLASS_VALUE (name))
+ return;
- for (fields = TYPE_FIELDS (type); fields; fields = TREE_CHAIN (fields))
+ /* First, deal with the type binding. */
+ if (type_binding_p)
{
- if (dummy && TREE_CODE (fields) != TYPE_DECL)
- continue;
-
- /* Unmark so that if we are in a constructor, and then find that
- this field was initialized by a base initializer,
- we can emit an error message. */
- if (TREE_CODE (fields) == FIELD_DECL)
- TREE_USED (fields) = 0;
-
- /* Recurse into anonymous unions. */
- if (DECL_NAME (fields) == NULL_TREE
- && TREE_CODE (TREE_TYPE (fields)) == UNION_TYPE)
- {
- dfs_pushdecls (TYPE_BINFO (TREE_TYPE (fields)), data);
- continue;
- }
-
- if (DECL_NAME (fields))
+ type_binding = lookup_member (current_class_type, name,
+ /*protect=*/2,
+ /*want_type=*/1);
+ if (TREE_CODE (type_binding) == TREE_LIST
+ && TREE_TYPE (type_binding) == error_mark_node)
+ /* NAME is ambiguous. */
+ push_class_level_binding (name, type_binding);
+ else
+ pushdecl_class_level (type_binding);
+ }
+
+ /* Now, do the value binding. */
+ value_binding = lookup_member (current_class_type, name,
+ /*protect=*/2,
+ /*want_type=*/0);
+
+ if (type_binding_p
+ && (TREE_CODE (value_binding) == TYPE_DECL
+ || (TREE_CODE (value_binding) == TREE_LIST
+ && TREE_TYPE (value_binding) == error_mark_node
+ && (TREE_CODE (TREE_VALUE (value_binding))
+ == TYPE_DECL))))
+ /* We found a type-binding, even when looking for a non-type
+ binding. This means that we already processed this binding
+ above. */
+ my_friendly_assert (type_binding_p, 19990401);
+ else if (value_binding)
+ {
+ if (TREE_CODE (value_binding) == TREE_LIST
+ && TREE_TYPE (value_binding) == error_mark_node)
+ /* NAME is ambiguous. */
+ push_class_level_binding (name, value_binding);
+ else
{
- tree name = DECL_NAME (fields);
- tree class_value = IDENTIFIER_CLASS_VALUE (name);
-
- /* If the class value is not an envelope of the kind described in
- the comment above, we create a new envelope. */
- maybe_push_cache_obstack ();
- if (class_value == NULL_TREE || TREE_CODE (class_value) != TREE_LIST
- || TREE_PURPOSE (class_value) == NULL_TREE
- || TREE_CODE (TREE_PURPOSE (class_value)) == IDENTIFIER_NODE)
- {
- /* See comment above for a description of envelopes. */
- *closed_envelopes = tree_cons (NULL_TREE, class_value,
- *closed_envelopes);
- IDENTIFIER_CLASS_VALUE (name) = *closed_envelopes;
- class_value = IDENTIFIER_CLASS_VALUE (name);
- }
-
- envelope_add_decl (type, fields, &TREE_PURPOSE (class_value));
- pop_obstacks ();
+ if (BASELINK_P (value_binding))
+ /* NAME is some overloaded functions. */
+ value_binding = TREE_VALUE (value_binding);
+ pushdecl_class_level (value_binding);
}
}
+}
- method_vec = CLASS_TYPE_P (type) ? CLASSTYPE_METHOD_VEC (type) : NULL_TREE;
- if (method_vec && ! dummy)
- {
- tree *methods;
- tree *end;
-
- /* Farm out constructors and destructors. */
- end = TREE_VEC_END (method_vec);
-
- for (methods = &TREE_VEC_ELT (method_vec, 2);
- *methods && methods != end;
- methods++)
- {
- /* This will cause lookup_name to return a pointer
- to the tree_list of possible methods of this name. */
- tree name;
- tree class_value;
-
-
- name = DECL_NAME (OVL_CURRENT (*methods));
- class_value = IDENTIFIER_CLASS_VALUE (name);
-
- maybe_push_cache_obstack ();
+/* Push class-level declarations for any names appearing in BINFO that
+ are TYPE_DECLS. */
- /* If the class value is not an envelope of the kind described in
- the comment above, we create a new envelope. */
- if (class_value == NULL_TREE || TREE_CODE (class_value) != TREE_LIST
- || TREE_PURPOSE (class_value) == NULL_TREE
- || TREE_CODE (TREE_PURPOSE (class_value)) == IDENTIFIER_NODE)
- {
- /* See comment above for a description of envelopes. */
- *closed_envelopes = tree_cons (NULL_TREE, class_value,
- *closed_envelopes);
- IDENTIFIER_CLASS_VALUE (name) = *closed_envelopes;
- class_value = IDENTIFIER_CLASS_VALUE (name);
- }
+static tree
+dfs_push_type_decls (binfo, data)
+ tree binfo;
+ void *data ATTRIBUTE_UNUSED;
+{
+ tree type;
+ tree fields;
- /* Here we try to rule out possible ambiguities.
- If we can't do that, keep a TREE_LIST with possibly ambiguous
- decls in there. */
- /* Arbitrarily choose the first function in the list. This is OK
- because this is only used for initial lookup; anything that
- actually uses the function will look it up again. */
- envelope_add_decl (type, OVL_CURRENT (*methods),
- &TREE_PURPOSE (class_value));
- pop_obstacks ();
- }
- }
+ type = BINFO_TYPE (binfo);
+ for (fields = TYPE_FIELDS (type); fields; fields = TREE_CHAIN (fields))
+ if (DECL_NAME (fields) && TREE_CODE (fields) == TYPE_DECL
+ && !(!same_type_p (type, current_class_type)
+ && template_self_reference_p (type, fields)))
+ setup_class_bindings (DECL_NAME (fields), /*type_binding_p=*/1);
/* We can't just use BINFO_MARKED because envelope_add_decl uses
DERIVED_FROM_P, which calls get_base_distance. */
SET_BINFO_PUSHDECLS_MARKED (binfo);
-
+
return NULL_TREE;
}
-/* Consolidate unique (by name) member functions. */
+/* Push class-level declarations for any names appearing in BINFO that
+ are not TYPE_DECLS. */
static tree
-dfs_compress_decls (binfo, data)
+dfs_push_decls (binfo, data)
tree binfo;
- void *data ATTRIBUTE_UNUSED;
+ void *data;
{
- tree type = BINFO_TYPE (binfo);
- tree method_vec
- = CLASS_TYPE_P (type) ? CLASSTYPE_METHOD_VEC (type) : NULL_TREE;
+ tree type;
+ tree method_vec;
+ int dep_base_p;
+
+ type = BINFO_TYPE (binfo);
+ dep_base_p = (processing_template_decl && type != current_class_type
+ && dependent_base_p (binfo));
+ if (!dep_base_p)
+ {
+ tree fields;
+ for (fields = TYPE_FIELDS (type); fields; fields = TREE_CHAIN (fields))
+ if (DECL_NAME (fields)
+ && TREE_CODE (fields) != TYPE_DECL
+ && TREE_CODE (fields) != USING_DECL)
+ setup_class_bindings (DECL_NAME (fields), /*type_binding_p=*/0);
+ else if (TREE_CODE (fields) == FIELD_DECL
+ && ANON_AGGR_TYPE_P (TREE_TYPE (fields)))
+ dfs_push_decls (TYPE_BINFO (TREE_TYPE (fields)), data);
+
+ method_vec = (CLASS_TYPE_P (type)
+ ? CLASSTYPE_METHOD_VEC (type) : NULL_TREE);
+ if (method_vec)
+ {
+ tree *methods;
+ tree *end;
- if (processing_template_decl && type != current_class_type
- && dependent_base_p (binfo))
- /* We only record types if we're a template base. */;
- else if (method_vec != 0)
- {
- /* Farm out constructors and destructors. */
- tree *methods;
- tree *end = TREE_VEC_END (method_vec);
+ /* Farm out constructors and destructors. */
+ end = TREE_VEC_END (method_vec);
- for (methods = &TREE_VEC_ELT (method_vec, 2);
- methods != end && *methods; methods++)
- {
- /* This is known to be an envelope of the kind described before
- dfs_pushdecls. */
- tree class_value =
- IDENTIFIER_CLASS_VALUE (DECL_NAME (OVL_CURRENT (*methods)));
- tree tmp = TREE_PURPOSE (class_value);
-
- /* This was replaced in scope by somebody else. Just leave it
- alone. */
- if (TREE_CODE (tmp) != TREE_LIST)
- continue;
-
- if (TREE_CHAIN (tmp) == NULL_TREE
- && TREE_VALUE (tmp)
- && OVL_NEXT (TREE_VALUE (tmp)) == NULL_TREE)
- {
- TREE_PURPOSE (class_value) = TREE_VALUE (tmp);
- }
+ for (methods = &TREE_VEC_ELT (method_vec, 2);
+ *methods && methods != end;
+ methods++)
+ setup_class_bindings (DECL_NAME (OVL_CURRENT (*methods)),
+ /*type_binding_p=*/0);
}
}
+
CLEAR_BINFO_PUSHDECLS_MARKED (binfo);
return NULL_TREE;
push_class_decls (type)
tree type;
{
- struct obstack *ambient_obstack = current_obstack;
- tree closed_envelopes = NULL_TREE;
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. */
- maybe_push_cache_obstack ();
+ /* Enter type declarations and mark. */
+ dfs_walk (TYPE_BINFO (type), dfs_push_type_decls, unmarked_pushdecls_p, 0);
- /* Push class fields into CLASS_VALUE scope, and mark. */
- dfs_walk (TYPE_BINFO (type), dfs_pushdecls, unmarked_pushdecls_p,
- &closed_envelopes);
-
- /* Compress fields which have only a single entry
- by a given name, and unmark. */
- dfs_walk (TYPE_BINFO (type), dfs_compress_decls, marked_pushdecls_p,
- 0);
-
- /* Open up all the closed envelopes and push the contained decls into
- class scope. */
- while (closed_envelopes)
- {
- tree new = TREE_PURPOSE (closed_envelopes);
- tree id;
-
- /* This is messy because the class value may be a *_DECL, or a
- TREE_LIST of overloaded *_DECLs or even a TREE_LIST of ambiguous
- *_DECLs. The name is stored at different places in these three
- cases. */
- if (TREE_CODE (new) == TREE_LIST)
- {
- if (TREE_PURPOSE (new) != NULL_TREE)
- id = TREE_PURPOSE (new);
- else
- {
- tree node = TREE_VALUE (new);
-
- if (TREE_CODE (node) == TYPE_DECL
- && DECL_ARTIFICIAL (node)
- && IS_AGGR_TYPE (TREE_TYPE (node))
- && CLASSTYPE_TEMPLATE_INFO (TREE_TYPE (node)))
- {
- tree t = CLASSTYPE_TI_TEMPLATE (TREE_TYPE (node));
- tree n = new;
-
- for (; n; n = TREE_CHAIN (n))
- {
- tree d = TREE_VALUE (n);
- if (TREE_CODE (d) == TYPE_DECL
- && DECL_ARTIFICIAL (node)
- && IS_AGGR_TYPE (TREE_TYPE (d))
- && CLASSTYPE_TEMPLATE_INFO (TREE_TYPE (d))
- && CLASSTYPE_TI_TEMPLATE (TREE_TYPE (d)) == t)
- /* OK */;
- else
- break;
- }
-
- if (n == NULL_TREE)
- new = t;
- }
- else while (TREE_CODE (node) == TREE_LIST)
- node = TREE_VALUE (node);
- id = DECL_NAME (node);
- }
- }
- else
- id = DECL_NAME (new);
-
- /* Install the original class value in order to make
- pushdecl_class_level work correctly. */
- IDENTIFIER_CLASS_VALUE (id) = TREE_VALUE (closed_envelopes);
- if (TREE_CODE (new) == TREE_LIST)
- push_class_level_binding (id, new);
- else
- pushdecl_class_level (new);
- closed_envelopes = TREE_CHAIN (closed_envelopes);
- }
-
- /* Undo the call to maybe_push_cache_obstack above. */
- pop_obstacks ();
-
- current_obstack = ambient_obstack;
+ /* Enter non-type declarations and unmark. */
+ dfs_walk (TYPE_BINFO (type), dfs_push_decls, marked_pushdecls_p, 0);
}
/* Here's a subroutine we need because C lacks lambdas. */
TREE_USED (fields) = 0;
if (DECL_NAME (fields) == NULL_TREE
- && TREE_CODE (TREE_TYPE (fields)) == UNION_TYPE)
+ && ANON_AGGR_TYPE_P (TREE_TYPE (fields)))
unuse_fields (TREE_TYPE (fields));
}
init_search_processing ()
{
gcc_obstack_init (&search_obstack);
- _vptr_name = get_identifier ("_vptr");
+ vptr_identifier = get_identifier ("_vptr");
}
void
#endif /* GATHER_STATISTICS */
}
-#define scratch_tree_cons expr_tree_cons
-
static tree
add_conversions (binfo, data)
tree binfo;
tree method_vec = CLASSTYPE_METHOD_VEC (BINFO_TYPE (binfo));
tree *conversions = (tree *) data;
+ /* Some builtin types have no method vector, not even an empty one. */
+ if (!method_vec)
+ return NULL_TREE;
+
for (i = 2; i < TREE_VEC_LENGTH (method_vec); ++i)
{
tree tmp = TREE_VEC_ELT (method_vec, i);
/* 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 NULL_TREE;
}
+/* Return a TREE_LIST containing all the non-hidden user-defined
+ conversion functions for TYPE (and its base-classes). The
+ TREE_VALUE of each node is a FUNCTION_DECL or an OVERLOAD
+ containing the conversion functions. The TREE_PURPOSE is the BINFO
+ from which the conversion functions in this node were selected. */
+
tree
lookup_conversions (type)
tree type;
return oi.found_overlap;
}
-struct bfv_info {
- tree vbases;
- tree var;
-};
+/* Given a vtable VAR, determine which binfo it comes from.
-static tree
-dfs_bfv_queue_p (binfo, data)
- tree binfo;
- void *data;
+ FIXME What about secondary vtables? */
+
+tree
+binfo_for_vtable (var)
+ tree var;
{
- struct bfv_info *bfvi = (struct bfv_info *) data;
+ tree binfo = TYPE_BINFO (DECL_CONTEXT (var));
+ tree binfos;
+ int i;
- /* 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;
-}
+ while (1)
+ {
+ binfos = BINFO_BASETYPES (binfo);
+ if (binfos == NULL_TREE)
+ break;
-/* Passed to dfs_search by binfo_for_vtable; determine if bvtable comes
- from BINFO. */
+ i = CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
+ if (i == -1)
+ break;
-static tree
-dfs_bfv_helper (binfo, data)
- tree binfo;
- void *data;
-{
- struct bfv_info *bfvi = (struct bfv_info *) data;
+ binfo = TREE_VEC_ELT (binfos, i);
+ }
- if (BINFO_VTABLE (binfo) == bfvi->var)
- return binfo;
- return NULL_TREE;
+ return binfo;
}
-/* Given a vtable VAR, determine which binfo it comes from. */
+/* Returns 1 iff BINFO is from a direct or indirect virtual base. */
-tree
-binfo_for_vtable (var)
- tree var;
+int
+binfo_from_vbase (binfo)
+ tree binfo;
{
- tree type;
- struct bfv_info bfvi;
-
- type = DECL_CONTEXT (var);
- bfvi.vbases = CLASSTYPE_VBASECLASSES (type);
- return dfs_walk_real (TYPE_BINFO (type),
- 0, dfs_bfv_helper, dfs_bfv_queue_p, &bfvi);
+ for (; binfo; binfo = BINFO_INHERITANCE_CHAIN (binfo))
+ {
+ if (TREE_VIA_VIRTUAL (binfo))
+ return 1;
+ }
+ return 0;
}