/* 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 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 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 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_push_type_decls PROTO((tree, void *));
-static tree dfs_push_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 int protected_accessible_p PROTO ((tree, tree, tree, tree));
-static int friend_accessible_p PROTO ((tree, tree, tree, tree));
-static void setup_class_bindings PROTO ((tree, int));
-static int template_self_reference_p PROTO ((tree, tree));
+static 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
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 (friend_accessible_p (DECL_CLASS_CONTEXT (scope), type,
- decl, binfo))
+ 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. */
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. */
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;
protected_ok = friend_accessible_p (current_scope (),
type, decl, binfo);
- /* 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. */
+ /* 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);
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
- particular to the current specialization with the name of the
- template itself. For example:
+/* 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; }
/* 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";
}
}
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 two 2, we return a TREE_LIST whose
- TREE_PURPOSE is error_mark_node and whose TREE_VALUE is the list of
+ 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.
WANT_TYPE is 1 when we should only return TYPE_DECLs, if no
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;
}
if (protect == 2)
{
if (lfi.ambiguous)
- {
- /* An ERROR_MARK for the TREE_TYPE tells hack_identifier
- that the lookup is ambiguous. */
- TREE_TYPE (lfi.ambiguous) = error_mark_node;
- return scratch_tree_cons (error_mark_node,
- lfi.ambiguous,
- NULL_TREE);
- }
+ return lfi.ambiguous;
else
protect = 0;
}
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;
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);
}
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;
}
+/* Check that virtual overrider OVERRIDER is acceptable for base function
+ BASEFN. Issue diagnostic, and return zero, if unacceptable. */
+
+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");
+
+ 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.
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, 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_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;
+}
+
+/* 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. 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);
+}
+
+/* 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 type = (tree) data;
+
+ if (TREE_CODE (type) == TREE_LIST)
+ type = TREE_PURPOSE (type);
+
+ /* 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;
+}
+
+/* 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
+dfs_unmarked_real_bases_queue_p (binfo, data)
+ tree binfo;
+ void *data;
+{
+ binfo = get_shared_vbase_if_not_primary (binfo, data);
+ 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;
+{
+ 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;
}
-/* 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 that skips all virtual bases (and their
+ bases). */
tree
-get_abstract_virtuals (type)
+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 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);
+
+ return NULL_TREE;
+}
+
+/* Set CLASSTYPE_PURE_VIRTUALS for TYPE. */
+
+void
+get_pure_virtuals (type)
tree type;
{
tree vbases;
- tree abstract_virtuals = NULL;
- /* 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))
+ /* 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 = BINFO_VIRTUALS (vbases);
+ tree virtuals;
- skip_rtti_stuff (&virtuals, type);
-
- while (virtuals)
+ for (virtuals = skip_rtti_stuff (vbases, BINFO_TYPE (vbases), NULL);
+ virtuals;
+ virtuals = TREE_CHAIN (virtuals))
{
- tree base_pfn = FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (virtuals));
- tree base_fndecl = TREE_OPERAND (base_pfn, 0);
+ 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
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);
+ for (i = CLASSTYPE_N_BASECLASSES (derived) - 1; i >= 0; --i)
+ {
+ 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);
+ }
+
+ 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, t);
+ 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. */
+
+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;
- 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. */
+ 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;
+}
+
+/* Find the real occurrence of the virtual BASE (a class type) in the
+ hierarchy dominated by TYPE. */
- /* unmark marked vbases */
- for (vbases = vbase_types; vbases; vbases = TREE_CHAIN (vbases))
- CLEAR_BINFO_VBASE_MARKED (vbases);
+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 vbase_types;
+ 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 (). */
/*protect=*/2,
/*want_type=*/1);
if (TREE_CODE (type_binding) == TREE_LIST
- && TREE_PURPOSE (type_binding) == error_mark_node)
+ && TREE_TYPE (type_binding) == error_mark_node)
/* NAME is ambiguous. */
- push_class_level_binding (name, TREE_VALUE (type_binding));
+ push_class_level_binding (name, type_binding);
else
pushdecl_class_level (type_binding);
}
if (type_binding_p
&& (TREE_CODE (value_binding) == TYPE_DECL
|| (TREE_CODE (value_binding) == TREE_LIST
- && TREE_PURPOSE (value_binding) == error_mark_node
- && (TREE_CODE (TREE_VALUE (TREE_VALUE (value_binding)))
+ && 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
+ else if (value_binding)
{
if (TREE_CODE (value_binding) == TREE_LIST
- && TREE_PURPOSE (value_binding) == error_mark_node)
+ && TREE_TYPE (value_binding) == error_mark_node)
/* NAME is ambiguous. */
- push_class_level_binding (name, TREE_VALUE (value_binding));
+ push_class_level_binding (name, value_binding);
else
{
- if (TREE_CODE (value_binding) == TREE_LIST)
+ if (BASELINK_P (value_binding))
/* NAME is some overloaded functions. */
value_binding = TREE_VALUE (value_binding);
pushdecl_class_level (value_binding);
&& TREE_CODE (fields) != USING_DECL)
setup_class_bindings (DECL_NAME (fields), /*type_binding_p=*/0);
else if (TREE_CODE (fields) == FIELD_DECL
- && ANON_UNION_TYPE_P (TREE_TYPE (fields)))
+ && ANON_AGGR_TYPE_P (TREE_TYPE (fields)))
dfs_push_decls (TYPE_BINFO (TREE_TYPE (fields)), data);
method_vec = (CLASS_TYPE_P (type)
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. */
- maybe_push_cache_obstack ();
-
- /* Push class fields into CLASS_VALUE scope, and mark. */
+ /* Enter type declarations and mark. */
dfs_walk (TYPE_BINFO (type), dfs_push_type_decls, unmarked_pushdecls_p, 0);
- /* Compress fields which have only a single entry
- by a given name, and unmark. */
+ /* Enter non-type declarations and unmark. */
dfs_walk (TYPE_BINFO (type), dfs_push_decls, marked_pushdecls_p, 0);
-
- /* Undo the call to maybe_push_cache_obstack above. */
- pop_obstacks ();
-
- current_obstack = ambient_obstack;
}
/* 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_walk_real 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;
}