/* Breadth-first and depth-first routines for
searching multiple-inheritance lattice for GNU C++.
- Copyright (C) 1987, 89, 92-96, 1997 Free Software Foundation, Inc.
+ Copyright (C) 1987, 89, 92-97, 1998, 1999, 2000 Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com)
This file is part of GNU CC.
#define 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_1 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 get_template_base_recursive
- PROTO((tree, tree, tree, int));
-static void dfs_walk PROTO((tree, void (*) (tree), int (*) (tree)));
-static void dfs_check_overlap PROTO((tree));
-static int dfs_no_overlap_yet PROTO((tree));
-static void envelope_add_decl PROTO((tree, tree, tree *));
+static tree dfs_check_overlap PROTO((tree, void *));
+static tree dfs_no_overlap_yet PROTO((tree, void *));
static int get_base_distance_recursive
PROTO((tree, int, int, int, int *, tree *, tree,
int, int *, int, int));
+static int dynamic_cast_base_recurse PROTO((tree, tree, int, tree *));
static void expand_upcast_fixups
PROTO((tree, tree, tree, tree, tree, tree, tree *));
static void fixup_virtual_upcast_offsets
PROTO((tree, tree, int, int, tree, tree, tree, tree,
tree *));
-static int markedp PROTO((tree));
-static int unmarkedp PROTO((tree));
-static int marked_vtable_pathp PROTO((tree));
-static int unmarked_vtable_pathp PROTO((tree));
-static int marked_new_vtablep PROTO((tree));
-static int unmarked_new_vtablep PROTO((tree));
-static int dfs_debug_unmarkedp PROTO((tree));
-static void dfs_debug_mark PROTO((tree));
-static void dfs_find_vbases PROTO((tree));
-static void dfs_clear_vbase_slots PROTO((tree));
-static void dfs_unmark PROTO((tree));
-static void dfs_init_vbase_pointers PROTO((tree));
-static void dfs_get_vbase_types PROTO((tree));
-static void dfs_pushdecls PROTO((tree));
-static void dfs_compress_decls PROTO((tree));
-static void dfs_unuse_fields PROTO((tree));
-static tree add_conversions PROTO((tree));
-static tree get_virtuals_named_this PROTO((tree));
-static tree get_virtual_destructor PROTO((tree));
-static int tree_has_any_destructor_p PROTO((tree));
+static tree marked_vtable_pathp PROTO((tree, void *));
+static tree unmarked_vtable_pathp PROTO((tree, void *));
+static tree marked_new_vtablep PROTO((tree, void *));
+static tree unmarked_new_vtablep PROTO((tree, void *));
+static tree marked_pushdecls_p PROTO((tree, void *));
+static tree unmarked_pushdecls_p PROTO((tree, void *));
+#if 0
+static tree dfs_debug_unmarkedp PROTO((tree, void *));
+static tree dfs_debug_mark PROTO((tree, void *));
+#endif
+static tree dfs_find_vbases PROTO((tree, void *));
+static tree dfs_clear_vbase_slots PROTO((tree, void *));
+static tree dfs_init_vbase_pointers PROTO((tree, void *));
+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 int check_final_overrider PROTO((tree, tree));
static struct search_level *push_search_level
PROTO((struct stack_level *, struct obstack *));
static struct search_level *pop_search_level
PROTO((struct stack_level *));
-static tree breadth_first_search
- PROTO((tree, tree (*) (tree), int (*) (tree)));
-
-static tree vbase_types;
-static tree vbase_decl_ptr_intermediate, vbase_decl_ptr;
-static tree vbase_init_result;
+static tree bfs_walk
+ PROTO((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 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 void fixup_all_virtual_upcast_offsets PROTO ((tree, tree));
+static tree dfs_mark_primary_bases PROTO((tree, void *));
+static tree get_shared_vbase_if_not_primary PROTO((tree, tree));
/* Allocate a level of searching. */
return stack;
}
\f
-static tree _vptr_name;
-
/* Variables for gathering statistics. */
#ifdef GATHER_STATISTICS
static int n_fields_searched;
static int n_contexts_saved;
#endif /* GATHER_STATISTICS */
-/* This list is used by push_class_decls to know what decls need to
- be pushed into class scope. */
-static tree closed_envelopes = NULL_TREE;
\f
/* Get a virtual binfo that is found inside BINFO's hierarchy that is
the same type as the type given in PARENT. To be optimal, we want
EXPR is a non-null POINTER_TYPE to RECORD_TYPE. We also know that
the type of what expr points to has a virtual base of type TYPE. */
-static tree
+tree
convert_pointer_to_vbase (type, expr)
tree type;
tree expr;
tree, deal with it. This happens when we are called from
expand_upcast_fixups. */
if (rval == -1 && TREE_CODE (parent) == TREE_VEC
- && parent == binfo_member (BINFO_TYPE (parent),
- CLASSTYPE_VBASECLASSES (type)))
+ && parent == BINFO_FOR_VBASE (BINFO_TYPE (parent), type))
{
my_friendly_assert (BINFO_INHERITANCE_CHAIN (parent) == binfo, 980827);
new_binfo = parent;
return rval;
}
+/* Worker function for get_dynamic_cast_base_type. */
+
+static int
+dynamic_cast_base_recurse (subtype, binfo, via_virtual, offset_ptr)
+ tree subtype;
+ tree binfo;
+ int via_virtual;
+ tree *offset_ptr;
+{
+ tree binfos;
+ int i, n_baselinks;
+ int worst = -3;
+
+ if (BINFO_TYPE (binfo) == subtype)
+ {
+ if (via_virtual)
+ return -2;
+ else
+ {
+ *offset_ptr = BINFO_OFFSET (binfo);
+ return 0;
+ }
+ }
+
+ binfos = BINFO_BASETYPES (binfo);
+ n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+ for (i = 0; i < n_baselinks; i++)
+ {
+ tree base_binfo = TREE_VEC_ELT (binfos, i);
+ int rval;
+
+ if (!TREE_VIA_PUBLIC (base_binfo))
+ continue;
+ rval = dynamic_cast_base_recurse
+ (subtype, base_binfo,
+ via_virtual || TREE_VIA_VIRTUAL (base_binfo), offset_ptr);
+ if (worst == -3)
+ worst = rval;
+ else if (rval >= 0)
+ worst = worst >= 0 ? -1 : worst;
+ else if (rval > -3)
+ worst = worst < rval ? worst : rval;
+ }
+ return worst;
+}
+
+/* The dynamic cast runtime needs a hint about how the static SUBTYPE type started
+ from is related to the required TARGET type, in order to optimize the
+ inheritance graph search. This information is independant of the
+ current context, and ignores private paths, hence get_base_distance is
+ inappropriate. Return a TREE specifying the base offset, BOFF.
+ BOFF >= 0, there is only one public non-virtual SUBTYPE base at offset BOFF,
+ and there are no public virtual SUBTYPE bases.
+ BOFF == -1, SUBTYPE occurs as multiple public non-virtual bases.
+ BOFF == -2, SUBTYPE occurs as multiple public virtual or non-virtual bases.
+ BOFF == -3, SUBTYPE is not a public base. */
+
+tree
+get_dynamic_cast_base_type (subtype, target)
+ tree subtype;
+ tree target;
+{
+ tree offset = NULL_TREE;
+ int boff = dynamic_cast_base_recurse (subtype, TYPE_BINFO (target),
+ 0, &offset);
+
+ if (!boff)
+ return offset;
+ return build_int_2 (boff, -1);
+}
+
/* Search for a member with name NAME in a multiple inheritance lattice
specified by TYPE. If it does not exist, return NULL_TREE.
If the member is ambiguously referenced, return `error_mark_node'.
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)
return temp;
}
- if (DECL_NAME (field) == name)
+ if (TREE_CODE (field) == USING_DECL)
+ /* For now, we're just treating member using declarations as
+ old ARM-style access declarations. Thus, there's no reason
+ to return a USING_DECL, and the rest of the compiler can't
+ handle it. Once the class is defined, these are purged
+ from TYPE_FIELDS anyhow; see handle_using_decl. */
+ ;
+ else if (DECL_NAME (field) == name)
{
if ((TREE_CODE(field) == VAR_DECL || TREE_CODE(field) == CONST_DECL)
&& DECL_ASSEMBLER_NAME (field) != NULL)
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;
}
-/* Compute the access of FIELD. This is done by computing
- the access available to each type in BASETYPES (which comes
- as a list of [via_public/basetype] in reverse order, namely base
- class before derived class). The first one which defines a
- access defines the access for the field. Otherwise, the
- access of the field is that which occurs normally.
+/* 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. */
- Uses global variables CURRENT_CLASS_TYPE and
- CURRENT_FUNCTION_DECL to use friend relationships
- if necessary.
+int
+at_function_scope_p ()
+{
+ tree cs = current_scope ();
+ return cs && TREE_CODE (cs) == FUNCTION_DECL;
+}
- This will be static when lookup_fnfield comes into this file.
+/* Return the scope of DECL, as appropriate when doing name-lookup. */
- access_public_node means that the field can be accessed by the current lexical
- scope.
+static tree
+context_for_name_lookup (decl)
+ tree decl;
+{
+ /* [class.union]
+
+ For the purposes of name lookup, after the anonymous union
+ 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);
+
+ while (TYPE_P (context) && ANON_AGGR_TYPE_P (context))
+ context = TYPE_CONTEXT (context);
+ if (!context)
+ context = global_namespace;
- access_protected_node means that the field cannot be accessed by the current
- lexical scope because it is protected.
+ return context;
+}
- access_private_node means that the field cannot be accessed by the current
- lexical scope because it is private. */
+/* Return a canonical BINFO if BINFO is a virtual base, or just BINFO
+ otherwise. */
-#if 0
-#define PUBLIC_RETURN return (DECL_PUBLIC (field) = 1), access_public_node
-#define PROTECTED_RETURN return (DECL_PROTECTED (field) = 1), access_protected_node
-#define PRIVATE_RETURN return (DECL_PRIVATE (field) = 1), access_private_node
-#else
-#define PUBLIC_RETURN return access_public_node
-#define PROTECTED_RETURN return access_protected_node
-#define PRIVATE_RETURN return access_private_node
-#endif
+static tree
+canonical_binfo (binfo)
+ tree binfo;
+{
+ return (TREE_VIA_VIRTUAL (binfo)
+ ? TYPE_BINFO (BINFO_TYPE (binfo)) : binfo);
+}
-#if 0
-/* Disabled with DECL_PUBLIC &c. */
-static tree previous_scope = NULL_TREE;
-#endif
+/* A queue function that simply ensures that we walk into the
+ canonical versions of virtual bases. */
-tree
-compute_access (basetype_path, field)
- tree basetype_path, field;
+static tree
+dfs_canonical_queue (binfo, data)
+ tree binfo;
+ void *data ATTRIBUTE_UNUSED;
{
- tree access;
- tree types;
- tree context;
- int protected_ok, via_protected;
- extern int flag_access_control;
-#if 1
- /* Replaces static decl above. */
- tree previous_scope;
-#endif
- int static_mem
- = ((TREE_CODE (field) == FUNCTION_DECL && DECL_STATIC_FUNCTION_P (field))
- || (TREE_CODE (field) != FUNCTION_DECL && TREE_STATIC (field)));
-
- if (! flag_access_control)
- return access_public_node;
+ return canonical_binfo (binfo);
+}
- /* The field lives in the current class. */
- if (BINFO_TYPE (basetype_path) == current_class_type)
- return access_public_node;
+/* Called via dfs_walk from assert_canonical_unmarked. */
-#if 0
- /* Disabled until pushing function scope clears these out. If ever. */
- /* Make these special cases fast. */
- if (current_scope () == previous_scope)
- {
- if (DECL_PUBLIC (field))
- return access_public_node;
- if (DECL_PROTECTED (field))
- return access_protected_node;
- if (DECL_PRIVATE (field))
- return access_private_node;
- }
-#endif
+static tree
+dfs_assert_unmarked_p (binfo, data)
+ tree binfo;
+ void *data ATTRIBUTE_UNUSED;
+{
+ my_friendly_assert (!BINFO_MARKED (binfo), 0);
+ return NULL_TREE;
+}
- /* We don't currently support access control on nested types. */
- if (TREE_CODE (field) == TYPE_DECL)
- return access_public_node;
+/* Asserts that all the nodes below BINFO (using the canonical
+ versions of virtual bases) are unmarked. */
- previous_scope = current_scope ();
+static void
+assert_canonical_unmarked (binfo)
+ tree binfo;
+{
+ dfs_walk (binfo, dfs_assert_unmarked_p, dfs_canonical_queue, 0);
+}
- context = DECL_REAL_CONTEXT (field);
+/* If BINFO is marked, return a canonical version of BINFO.
+ Otherwise, return NULL_TREE. */
- /* Fields coming from nested anonymous unions have their DECL_CLASS_CONTEXT
- slot set to the union type rather than the record type containing
- the anonymous union. */
- if (context && ANON_UNION_TYPE_P (context)
- && TREE_CODE (field) == FIELD_DECL)
- context = TYPE_CONTEXT (context);
+static tree
+shared_marked_p (binfo, data)
+ tree binfo;
+ void *data;
+{
+ binfo = canonical_binfo (binfo);
+ return markedp (binfo, data);
+}
- /* Virtual function tables are never private. But we should know that
- we are looking for this, and not even try to hide it. */
- if (DECL_NAME (field) && VFIELD_NAME_P (DECL_NAME (field)) == 1)
- PUBLIC_RETURN;
-
- /* Member found immediately within object. */
- if (BINFO_INHERITANCE_CHAIN (basetype_path) == NULL_TREE)
- {
- /* Are we (or an enclosing scope) friends with the class that has
- FIELD? */
- if (is_friend (context, previous_scope))
- PUBLIC_RETURN;
-
- /* If it's private, it's private, you letch. */
- if (TREE_PRIVATE (field))
- PRIVATE_RETURN;
-
- /* ARM $11.5. Member functions of a derived class can access the
- non-static protected members of a base class only through a
- pointer to the derived class, a reference to it, or an object
- of it. Also any subsequently derived classes also have
- access. */
- else if (TREE_PROTECTED (field))
- {
- if (current_class_type
- && (static_mem || DECL_CONSTRUCTOR_P (field))
- && ACCESSIBLY_DERIVED_FROM_P (context, current_class_type))
- PUBLIC_RETURN;
- else
- PROTECTED_RETURN;
- }
- else
- PUBLIC_RETURN;
- }
+/* If BINFO is not marked, return a canonical version of BINFO.
+ Otherwise, return NULL_TREE. */
- /* must reverse more than one element */
- basetype_path = reverse_path (basetype_path);
- types = basetype_path;
- via_protected = 0;
- access = access_default_node;
- protected_ok = static_mem && current_class_type
- && ACCESSIBLY_DERIVED_FROM_P (BINFO_TYPE (types), current_class_type);
+static tree
+shared_unmarked_p (binfo, data)
+ tree binfo;
+ void *data;
+{
+ binfo = canonical_binfo (binfo);
+ return unmarkedp (binfo, data);
+}
- while (1)
- {
- tree member;
- tree binfo = types;
- tree type = BINFO_TYPE (binfo);
- int private_ok = 0;
+/* Called from access_in_type via dfs_walk. Calculate the access to
+ DATA (which is really a DECL) in BINFO. */
- /* Friends of a class can see protected members of its bases.
- Note that classes are their own friends. */
- if (is_friend (type, previous_scope))
- {
- protected_ok = 1;
- private_ok = 1;
- }
+static tree
+dfs_access_in_type (binfo, data)
+ tree binfo;
+ void *data;
+{
+ tree decl = (tree) data;
+ tree type = BINFO_TYPE (binfo);
+ tree access = NULL_TREE;
- member = purpose_member (type, DECL_ACCESS (field));
- if (member)
+ if (context_for_name_lookup (decl) == type)
+ {
+ /* If we have desceneded to the scope of DECL, just note the
+ appropriate access. */
+ if (TREE_PRIVATE (decl))
+ access = access_private_node;
+ else if (TREE_PROTECTED (decl))
+ access = access_protected_node;
+ else
+ access = access_public_node;
+ }
+ else
+ {
+ /* First, check for an access-declaration that gives us more
+ access to the DECL. The CONST_DECL for an enumeration
+ constant will not have DECL_LANG_SPECIFIC, and thus no
+ DECL_ACCESS. */
+ if (DECL_LANG_SPECIFIC (decl))
{
- access = TREE_VALUE (member);
- break;
+ access = purpose_member (type, DECL_ACCESS (decl));
+ if (access)
+ access = TREE_VALUE (access);
}
- types = BINFO_INHERITANCE_CHAIN (types);
-
- /* If the next type was VIA_PROTECTED, then fields of all remaining
- classes past that one are *at least* protected. */
- if (types)
+ if (!access)
{
- if (TREE_VIA_PROTECTED (types))
- via_protected = 1;
- else if (! TREE_VIA_PUBLIC (types) && ! private_ok)
+ int i;
+ int n_baselinks;
+ tree binfos;
+
+ /* Otherwise, scan our baseclasses, and pick the most favorable
+ access. */
+ binfos = BINFO_BASETYPES (binfo);
+ n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+ for (i = 0; i < n_baselinks; ++i)
{
- access = access_private_node;
- break;
+ tree base_binfo = TREE_VEC_ELT (binfos, i);
+ tree base_access = TREE_CHAIN (canonical_binfo (base_binfo));
+
+ if (!base_access || base_access == access_private_node)
+ /* If it was not accessible in the base, or only
+ accessible as a private member, we can't access it
+ all. */
+ base_access = NULL_TREE;
+ else if (TREE_VIA_PROTECTED (base_binfo))
+ /* Public and protected members in the base are
+ protected here. */
+ base_access = access_protected_node;
+ else if (!TREE_VIA_PUBLIC (base_binfo))
+ /* Public and protected members in the base are
+ private here. */
+ base_access = access_private_node;
+
+ /* See if the new access, via this base, gives more
+ access than our previous best access. */
+ if (base_access &&
+ (base_access == access_public_node
+ || (base_access == access_protected_node
+ && access != access_public_node)
+ || (base_access == access_private_node
+ && !access)))
+ {
+ access = base_access;
+
+ /* If the new access is public, we can't do better. */
+ if (access == access_public_node)
+ break;
+ }
}
}
- else
- break;
}
- /* No special visibilities apply. Use normal rules. */
+ /* Note the access to DECL in TYPE. */
+ TREE_CHAIN (binfo) = access;
+
+ /* Mark TYPE as visited so that if we reach it again we do not
+ duplicate our efforts here. */
+ SET_BINFO_MARKED (binfo);
+
+ return NULL_TREE;
+}
+
+/* Return the access to DECL in TYPE. */
+
+static tree
+access_in_type (type, decl)
+ tree type;
+ tree decl;
+{
+ tree binfo = TYPE_BINFO (type);
+
+ /* We must take into account
+
+ [class.paths]
+
+ If a name can be reached by several paths through a multiple
+ inheritance graph, the access is that of the path that gives
+ most access.
+
+ The algorithm we use is to make a post-order depth-first traversal
+ of the base-class hierarchy. As we come up the tree, we annotate
+ each node with the most lenient access. */
+ dfs_walk_real (binfo, 0, dfs_access_in_type, shared_unmarked_p, decl);
+ dfs_walk (binfo, dfs_unmark, shared_marked_p, 0);
+ assert_canonical_unmarked (binfo);
+
+ return TREE_CHAIN (binfo);
+}
+
+/* Called from dfs_accessible_p via dfs_walk. */
+
+static tree
+dfs_accessible_queue_p (binfo, data)
+ tree binfo;
+ void *data ATTRIBUTE_UNUSED;
+{
+ if (BINFO_MARKED (binfo))
+ return NULL_TREE;
+
+ /* If this class is inherited via private or protected inheritance,
+ then we can't see it, unless we are a friend of the subclass. */
+ if (!TREE_VIA_PUBLIC (binfo)
+ && !is_friend (BINFO_TYPE (BINFO_INHERITANCE_CHAIN (binfo)),
+ current_scope ()))
+ return NULL_TREE;
+
+ return canonical_binfo (binfo);
+}
+
+/* Called from dfs_accessible_p via dfs_walk. */
+
+static tree
+dfs_accessible_p (binfo, data)
+ tree binfo;
+ void *data;
+{
+ int protected_ok = data != 0;
+ tree access;
+
+ /* We marked the binfos while computing the access in each type.
+ So, we unmark as we go now. */
+ SET_BINFO_MARKED (binfo);
+
+ access = TREE_CHAIN (binfo);
+ if (access == access_public_node
+ || (access == access_protected_node && protected_ok))
+ return binfo;
+ else if (access && is_friend (BINFO_TYPE (binfo), current_scope ()))
+ return binfo;
+
+ 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;
+
+ 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))
+ 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;
+}
+
+/* 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
+ 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. */
+
+int
+accessible_p (type, decl)
+ tree type;
+ tree decl;
+
+{
+ tree binfo;
+ tree t;
+
+ /* Non-zero if it's OK to access DECL if it has protected
+ accessibility in TYPE. */
+ int protected_ok = 0;
+
+ /* If we're not checking access, everything is accessible. */
+ if (!flag_access_control)
+ return 1;
+
+ /* If this declaration is in a block or namespace scope, there's no
+ access control. */
+ 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 (access == access_default_node)
+ if (!TYPE_P (type))
{
- if (is_friend (context, previous_scope))
- access = access_public_node;
- else if (TREE_PRIVATE (field))
- access = access_private_node;
- else if (TREE_PROTECTED (field))
- access = access_protected_node;
- else
- access = access_public_node;
+ binfo = type;
+ type = BINFO_TYPE (type);
}
+ else
+ binfo = TYPE_BINFO (type);
- if (access == access_public_node && via_protected)
- access = access_protected_node;
+ /* [class.access.base]
- if (access == access_protected_node && protected_ok)
- access = access_public_node;
+ A member m is accessible when named in class N if
-#if 0
- if (access == access_public_node)
- DECL_PUBLIC (field) = 1;
- else if (access == access_protected_node)
- DECL_PROTECTED (field) = 1;
- else if (access == access_private_node)
- DECL_PRIVATE (field) = 1;
- else my_friendly_abort (96);
-#endif
- return access;
+ --m as a member of N is public, or
+
+ --m as a member of N is private, and the reference occurs in a
+ member or friend of class N, or
+
+ --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, or
+
+ --there exists a base class B of N that is accessible at the point
+ of reference, and m is accessible when named in class B.
+
+ We walk the base class hierarchy, checking these conditions. */
+
+ /* 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)
+ 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 on the same that will 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
+ dominated by type. */
+ access_in_type (type, decl);
+ /* Walk the hierarchy again, looking for a base class that allows
+ access. */
+ t = dfs_walk (binfo, dfs_accessible_p,
+ dfs_accessible_queue_p,
+ protected_ok ? &protected_ok : 0);
+ /* Clear any mark bits. Note that we have to walk the whole tree
+ here, since we have aborted the previous walk from some point
+ deep in the tree. */
+ dfs_walk (binfo, dfs_unmark, dfs_canonical_queue, 0);
+ assert_canonical_unmarked (binfo);
+
+ return t != NULL_TREE;
}
/* Routine to see if the sub-object denoted by the binfo PARENT can be
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;
+
+ /* 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 = TREE_VEC_ELT (binfos, i);
- if (TREE_VIA_VIRTUAL (base_binfo))
- base_binfo = TYPE_BINFO (BINFO_TYPE (base_binfo));
+ 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;
}
return -1;
}
-/* Look for a field 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.
+struct lookup_field_info {
+ /* The type in which we're looking. */
+ tree type;
+ /* The name of the field for which we're looking. */
+ tree name;
+ /* If non-NULL, the current result of the lookup. */
+ tree rval;
+ /* The path to RVAL. */
+ tree rval_binfo;
+ /* If non-NULL, the lookup was ambiguous, and this is a list of the
+ candidates. */
+ tree ambiguous;
+ /* If non-zero, we are looking for types, not data members. */
+ int want_type;
+ /* 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. */
+ const char *errstr;
+};
+
+/* Returns non-zero if BINFO is not hidden by the value found by the
+ lookup so far. If BINFO is hidden, then there's no need to look in
+ it. DATA is really a struct lookup_field_info. Called from
+ lookup_field via breadth_first_search. */
- 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. */
-
-tree
-lookup_field (xbasetype, name, protect, want_type)
- register tree xbasetype, name;
- int protect, want_type;
+static tree
+lookup_field_queue_p (binfo, data)
+ tree binfo;
+ void *data;
{
- int head = 0, tail = 0;
- tree rval, rval_binfo = NULL_TREE, rval_binfo_h = NULL_TREE;
- tree type = NULL_TREE, basetype_chain, basetype_path = NULL_TREE;
- tree this_v = access_default_node;
- tree entry, binfo, binfo_h;
- tree own_access = access_default_node;
- int vbase_name_p = VBASE_NAME_P (name);
-
- /* rval_binfo is the binfo associated with the found member, note,
- this can be set with useful information, even when rval is not
- set, because it must deal with ALL members, not just non-function
- members. It is used for ambiguity checking and the hidden
- checks. Whereas rval is only set if a proper (not hidden)
- non-function member is found. */
+ struct lookup_field_info *lfi = (struct lookup_field_info *) data;
- /* 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) */
+ /* Don't look for constructors or destructors in base classes. */
+ if (lfi->name == ctor_identifier || lfi->name == dtor_identifier)
+ return NULL_TREE;
- char *errstr = 0;
+ /* If this base class is hidden by the best-known value so far, we
+ don't need to look. */
+ if (!lfi->from_dep_base_p && lfi->rval_binfo
+ && hides (lfi->rval_binfo, binfo))
+ return NULL_TREE;
-#if 0
- /* We cannot search for constructor/destructor names like this. */
- /* This can't go here, but where should it go? */
- /* If we are looking for a constructor in a templated type, use the
- unspecialized name, as that is how we store it. */
- if (IDENTIFIER_TEMPLATE (name))
- name = constructor_name (name);
-#endif
+ if (TREE_VIA_VIRTUAL (binfo))
+ 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
+ lookup_field via breadth_first_search. */
+
+static tree
+lookup_field_r (binfo, data)
+ tree binfo;
+ void *data;
+{
+ struct lookup_field_info *lfi = (struct lookup_field_info *) data;
+ tree type = BINFO_TYPE (binfo);
+ 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. */
+ 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 there is no declaration with the indicated name in this type,
+ then there's nothing to do. */
+ 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)
+ {
+ /* If the new declaration is not found via a dependent base, and
+ the old one was, then we must prefer the new one. We weren't
+ really supposed to be able to find the old one, so we don't
+ want to be affected by a specialization. Consider:
+
+ struct B { typedef int I; };
+ template <typename T> struct D1 : virtual public B {};
+ template <typename T> struct D :
+ public D1, virtual pubic B { I i; };
+
+ The `I' in `D<T>' is unambigousuly `B::I', regardless of how
+ D1 is specialized. */
+ lfi->from_dep_base_p = 0;
+ lfi->rval = NULL_TREE;
+ lfi->rval_binfo = NULL_TREE;
+ lfi->ambiguous = NULL_TREE;
+ lfi->errstr = 0;
+ }
+ else if (lfi->rval_binfo && !lfi->from_dep_base_p && from_dep_base_p)
+ /* Similarly, if the old declaration was not found via a dependent
+ base, and the new one is, ignore the new one. */
+ return NULL_TREE;
+
+ /* If the lookup already found a match, and the new value doesn't
+ hide the old one, we might have an ambiguity. */
+ if (lfi->rval_binfo && !hides (binfo, lfi->rval_binfo))
+ {
+ if (nval == lfi->rval && SHARED_MEMBER_P (nval))
+ /* The two things are really the same. */
+ ;
+ else if (hides (lfi->rval_binfo, binfo))
+ /* The previous value hides the new one. */
+ ;
+ else
+ {
+ /* 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 = tree_cons (NULL_TREE, lfi->rval, NULL_TREE);
+ TREE_TYPE (lfi->ambiguous) = error_mark_node;
+ }
+
+ /* Add the new value. */
+ 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
+ {
+ /* 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;
+
+ lfi->rval = nval;
+ lfi->from_dep_base_p = from_dep_base_p;
+ lfi->rval_binfo = binfo;
+ }
+
+ return NULL_TREE;
+}
+
+/* Look for a memer named NAME in an inheritance lattice dominated by
+ 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
+ TREEE_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
+ TYPE_DECL can be found return NULL_TREE. */
+
+tree
+lookup_member (xbasetype, name, protect, want_type)
+ register tree xbasetype, name;
+ int protect, want_type;
+{
+ tree rval, rval_binfo = NULL_TREE;
+ tree type = NULL_TREE, basetype_path = NULL_TREE;
+ struct lookup_field_info lfi;
+
+ /* rval_binfo is the binfo associated with the found member, note,
+ this can be set with useful information, even when rval is not
+ set, because it must deal with ALL members, not just non-function
+ members. It is used for ambiguity checking and the hidden
+ checks. Whereas rval is only set if a proper (not hidden)
+ non-function member is found. */
+
+ 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 */
- rval = lookup_field_1 (type, name);
-
- if (rval || lookup_fnfields_here (type, name) >= 0)
- {
- if (rval)
- {
- if (want_type)
- {
- if (TREE_CODE (rval) != TYPE_DECL)
- {
- rval = purpose_member (name, CLASSTYPE_TAGS (type));
- if (rval)
- rval = TYPE_MAIN_DECL (TREE_VALUE (rval));
- }
- }
- else
- {
- if (TREE_CODE (rval) == TYPE_DECL
- && lookup_fnfields_here (type, name) >= 0)
- rval = NULL_TREE;
- }
- }
-
- if (protect && rval)
- {
- if (TREE_PRIVATE (rval) | TREE_PROTECTED (rval))
- this_v = compute_access (basetype_path, rval);
- if (TREE_CODE (rval) == CONST_DECL)
- {
- if (this_v == access_private_node)
- errstr = "enum `%D' is a private value of class `%T'";
- else if (this_v == access_protected_node)
- errstr = "enum `%D' is a protected value of class `%T'";
- }
- else
- {
- if (this_v == access_private_node)
- errstr = "member `%D' is a private member of class `%T'";
- else if (this_v == access_protected_node)
- errstr = "member `%D' is a protected member of class `%T'";
- }
- }
-
- rval_binfo = basetype_path;
- goto out;
- }
-
- basetype_chain = build_expr_list (NULL_TREE, basetype_path);
-
- /* The ambiguity check relies upon breadth first searching. */
-
- search_stack = push_search_level (search_stack, &search_obstack);
- binfo = basetype_path;
- binfo_h = binfo;
-
- while (1)
+ bzero ((PTR) &lfi, sizeof (lfi));
+ lfi.type = type;
+ lfi.name = name;
+ lfi.want_type = want_type;
+ bfs_walk (basetype_path, &lookup_field_r, &lookup_field_queue_p, &lfi);
+ rval = lfi.rval;
+ rval_binfo = lfi.rval_binfo;
+ if (rval_binfo)
+ type = BINFO_TYPE (rval_binfo);
+ errstr = lfi.errstr;
+
+ /* If we are not interested in ambiguities, don't report them;
+ just return NULL_TREE. */
+ if (!protect && lfi.ambiguous)
+ return NULL_TREE;
+
+ if (protect == 2)
{
- tree binfos = BINFO_BASETYPES (binfo);
- int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
- tree nval;
-
- /* Process and/or queue base types. */
- for (i = 0; i < n_baselinks; i++)
- {
- tree base_binfo = TREE_VEC_ELT (binfos, i);
- if (BINFO_FIELDS_MARKED (base_binfo) == 0)
- {
- tree btypes;
-
- SET_BINFO_FIELDS_MARKED (base_binfo);
- btypes = scratch_tree_cons (NULL_TREE, base_binfo, basetype_chain);
- if (TREE_VIA_VIRTUAL (base_binfo))
- btypes = scratch_tree_cons (NULL_TREE,
- TYPE_BINFO (BINFO_TYPE (TREE_VEC_ELT (BINFO_BASETYPES (binfo_h), i))),
- btypes);
- else
- btypes = scratch_tree_cons (NULL_TREE,
- TREE_VEC_ELT (BINFO_BASETYPES (binfo_h), i),
- btypes);
- obstack_ptr_grow (&search_obstack, btypes);
- tail += 1;
- if (tail >= search_stack->limit)
- my_friendly_abort (98);
- }
- }
-
- /* Process head of queue, if one exists. */
- if (head >= tail)
- break;
-
- basetype_chain = search_stack->first[head++];
- binfo_h = TREE_VALUE (basetype_chain);
- basetype_chain = TREE_CHAIN (basetype_chain);
- basetype_path = TREE_VALUE (basetype_chain);
- if (TREE_CHAIN (basetype_chain))
- my_friendly_assert
- ((BINFO_INHERITANCE_CHAIN (basetype_path)
- == TREE_VALUE (TREE_CHAIN (basetype_chain)))
- /* We only approximate base info for partial instantiations. */
- || current_template_parms,
- 980827);
+ if (lfi.ambiguous)
+ return lfi.ambiguous;
else
- my_friendly_assert (BINFO_INHERITANCE_CHAIN (basetype_path)
- == NULL_TREE, 980827);
-
- binfo = basetype_path;
- type = BINFO_TYPE (binfo);
+ protect = 0;
+ }
- /* See if we can find NAME in TYPE. If RVAL is nonzero,
- and we do find NAME in TYPE, verify that such a second
- sighting is in fact valid. */
+ /* [class.access]
- nval = lookup_field_1 (type, name);
-
- if (nval || lookup_fnfields_here (type, name)>=0)
- {
- if (nval && nval == rval && SHARED_MEMBER_P (nval))
- {
- /* This is ok, the member found is the same [class.ambig] */
- }
- else if (rval_binfo && hides (rval_binfo_h, binfo_h))
- {
- /* This is ok, the member found is in rval_binfo, not
- here (binfo). */
- }
- else if (rval_binfo==NULL_TREE || hides (binfo_h, rval_binfo_h))
- {
- /* This is ok, the member found is here (binfo), not in
- rval_binfo. */
- if (nval)
- {
- rval = nval;
- if (protect)
- this_v = compute_access (basetype_path, rval);
- /* These may look ambiguous, but they really are not. */
- if (vbase_name_p)
- break;
- }
- else
- {
- /* Undo finding it before, as something else hides it. */
- rval = NULL_TREE;
- }
- rval_binfo = binfo;
- rval_binfo_h = binfo_h;
- }
- else
- {
- /* This is ambiguous. */
- errstr = "request for member `%D' is ambiguous";
- protect += 2;
- break;
- }
- }
- }
- {
- tree *tp = search_stack->first;
- tree *search_tail = tp + tail;
-
- if (rval_binfo)
- {
- type = BINFO_TYPE (rval_binfo);
-
- if (rval)
- {
- if (want_type)
- {
- if (TREE_CODE (rval) != TYPE_DECL)
- {
- rval = purpose_member (name, CLASSTYPE_TAGS (type));
- if (rval)
- rval = TYPE_MAIN_DECL (TREE_VALUE (rval));
- }
- }
- else
- {
- if (TREE_CODE (rval) == TYPE_DECL
- && lookup_fnfields_here (type, name) >= 0)
- rval = NULL_TREE;
- }
- }
- }
-
- if (rval == NULL_TREE)
- errstr = 0;
-
- /* If this FIELD_DECL defines its own access level, deal with that. */
- if (rval && errstr == 0
- && (protect & 1)
- && DECL_LANG_SPECIFIC (rval)
- && DECL_ACCESS (rval))
- {
- while (tp < search_tail)
- {
- /* If is possible for one of the derived types on the path to
- have defined special access for this field. Look for such
- declarations and report an error if a conflict is found. */
- tree new_v = NULL_TREE;
-
- if (this_v != access_default_node)
- new_v = compute_access (TREE_VALUE (TREE_CHAIN (*tp)), rval);
- if (this_v != access_default_node && new_v != this_v)
- {
- errstr = "conflicting access to member `%D'";
- this_v = access_default_node;
- }
- own_access = new_v;
- CLEAR_BINFO_FIELDS_MARKED (TREE_VALUE (TREE_CHAIN (*tp)));
- tp += 1;
- }
- }
- else
- {
- while (tp < search_tail)
- {
- CLEAR_BINFO_FIELDS_MARKED (TREE_VALUE (TREE_CHAIN (*tp)));
- tp += 1;
- }
- }
- }
- search_stack = pop_search_level (search_stack);
-
- if (errstr == 0)
- {
- if (own_access == access_private_node)
- errstr = "member `%D' declared private";
- else if (own_access == access_protected_node)
- errstr = "member `%D' declared protected";
- else if (this_v == access_private_node)
- errstr = TREE_PRIVATE (rval)
- ? "member `%D' is private"
- : "member `%D' is from private base class";
- else if (this_v == access_protected_node)
- errstr = TREE_PROTECTED (rval)
- ? "member `%D' is protected"
- : "member `%D' is from protected base class";
- }
-
- out:
- if (protect == 2)
- {
- /* If we are not interested in ambiguities, don't report them,
- just return NULL_TREE. */
- rval = NULL_TREE;
- 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)
+ && !enforce_access (xbasetype, rval))
+ return error_mark_node;
if (errstr && protect)
{
cp_error (errstr, name, type);
+ if (lfi.ambiguous)
+ print_candidates (lfi.ambiguous);
rval = error_mark_node;
}
- /* Do implicit typename stuff. This code also handles out-of-class
- definitions of nested classes whose enclosing class is a
- template. For example:
-
- template <class T> struct S { struct I { void f(); }; };
- template <class T> void S<T>::I::f() {}
+ /* If the thing we found was found via the implicit typename
+ extension, build the typename type. */
+ if (rval && lfi.from_dep_base_p && !DECL_CLASS_TEMPLATE_P (rval))
+ rval = TYPE_STUB_DECL (build_typename_type (BINFO_TYPE (basetype_path),
+ name, name,
+ TREE_TYPE (rval)));
- will come through here to handle `S<T>::I'. */
- if (rval && processing_template_decl
- && ! currently_open_class (BINFO_TYPE (rval_binfo))
- && uses_template_parms (type))
+ if (rval && is_overloaded_fn (rval))
{
- /* Don't return a non-type. Actually, we ought to return something
- so lookup_name_real can give a warning. */
- if (TREE_CODE (rval) != TYPE_DECL)
- return NULL_TREE;
-
- binfo = rval_binfo;
- for (; ; binfo = BINFO_INHERITANCE_CHAIN (binfo))
- if (BINFO_INHERITANCE_CHAIN (binfo) == NULL_TREE
- || (BINFO_TYPE (BINFO_INHERITANCE_CHAIN (binfo))
- == current_class_type))
- break;
-
- entry = build_typename_type (BINFO_TYPE (binfo), name, name,
- TREE_TYPE (rval));
- return TYPE_STUB_DECL (entry);
+ rval = tree_cons (basetype_path, rval, NULL_TREE);
+ SET_BASELINK_P (rval);
}
return rval;
}
-/* Try to find NAME inside a nested class. */
+/* Like lookup_member, except that if we find a function member we
+ return NULL_TREE. */
tree
-lookup_nested_field (name, complain)
- tree name;
- int complain;
+lookup_field (xbasetype, name, protect, want_type)
+ register tree xbasetype, name;
+ int protect, want_type;
{
- register tree t;
+ tree rval = lookup_member (xbasetype, name, protect, want_type);
+
+ /* Ignore functions. */
+ if (rval && TREE_CODE (rval) == TREE_LIST)
+ return NULL_TREE;
- 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;
+ return rval;
+}
- /* 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;
- }
+/* Like lookup_member, except that if we find a non-function member we
+ return NULL_TREE. */
- 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;
- }
- }
- }
+tree
+lookup_fnfields (xbasetype, name, protect)
+ register tree xbasetype, name;
+ int protect;
+{
+ tree rval = lookup_member (xbasetype, name, protect, /*want_type=*/0);
+
+ /* Ignore non-functions. */
+ if (rval && TREE_CODE (rval) != TREE_LIST)
+ return NULL_TREE;
- return id;
+ return rval;
}
/* 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. */
-static int
+int
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;
}
+\f
+/* Walk the class hierarchy dominated by TYPE. FN is called for each
+ type in the hierarchy, in a breadth-first preorder traversal. .
+ If it ever returns a non-NULL value, that value is immediately
+ returned and the walk is terminated. At each node FN, is passed a
+ BINFO indicating the path from the curently visited base-class to
+ TYPE. The TREE_CHAINs of the BINFOs may be used for scratch space;
+ they are otherwise unused. Before each base-class is walked QFN is
+ called. If the value returned is non-zero, the base-class is
+ walked; otherwise it is not. If QFN is NULL, it is treated as a
+ function which always returns 1. Both FN and QFN are passed the
+ DATA whenever they are called. */
-/* Starting from BASETYPE, return a TREE_BASELINK-like object
- which gives the following information (in a list):
-
- TREE_TYPE: list of basetypes needed to get to...
- TREE_VALUE: list of all functions in a given type
- which have name NAME.
-
- No access information is computed by this function,
- other then to adorn the list of basetypes with
- TREE_VIA_PUBLIC.
-
- If there are two ways to find a name (two members), if COMPLAIN is
- non-zero, then error_mark_node is returned, and an error message is
- printed, otherwise, just an error_mark_node is returned.
-
- As a special case, is COMPLAIN is -1, we don't complain, and we
- don't return error_mark_node, but rather the complete list of
- virtuals. This is used by get_virtuals_named_this. */
-
-tree
-lookup_fnfields (basetype_path, name, complain)
- tree basetype_path, name;
- int complain;
+static tree
+bfs_walk (binfo, fn, qfn, data)
+ tree binfo;
+ tree (*fn) PROTO((tree, void *));
+ tree (*qfn) PROTO((tree, void *));
+ void *data;
{
- int head = 0, tail = 0;
- tree type, rval, rval_binfo = NULL_TREE, rvals = NULL_TREE;
- tree rval_binfo_h = NULL_TREE, binfo, basetype_chain, binfo_h;
- int idx, find_all = 0;
-
- /* rval_binfo is the binfo associated with the found member, note,
- this can be set with useful information, even when rval is not
- set, because it must deal with ALL members, not just function
- members. It is used for ambiguity checking and the hidden
- checks. Whereas rval is only set if a proper (not hidden)
- 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) */
-
- /* For now, don't try this. */
- int protect = complain;
-
- char *errstr = 0;
-
- if (complain == -1)
- {
- find_all = 1;
- protect = complain = 0;
- }
-
-#if 0
- /* We cannot search for constructor/destructor names like this. */
- /* This can't go here, but where should it go? */
- /* If we are looking for a constructor in a templated type, use the
- unspecialized name, as that is how we store it. */
- if (IDENTIFIER_TEMPLATE (name))
- name = constructor_name (name);
-#endif
-
- binfo = basetype_path;
- binfo_h = binfo;
- type = complete_type (BINFO_TYPE (basetype_path));
-
-#ifdef GATHER_STATISTICS
- n_calls_lookup_fnfields++;
-#endif /* GATHER_STATISTICS */
-
- idx = lookup_fnfields_here (type, name);
- if (idx >= 0 || lookup_field_1 (type, name))
- {
- rval_binfo = basetype_path;
- rval_binfo_h = rval_binfo;
- }
-
- if (idx >= 0)
- {
- rval = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), idx);
- rvals = scratch_tree_cons (basetype_path, rval, rvals);
- if (BINFO_BASETYPES (binfo) && CLASSTYPE_BASELINK_VEC (type))
- TREE_TYPE (rvals) = TREE_VEC_ELT (CLASSTYPE_BASELINK_VEC (type), idx);
+ size_t head;
+ size_t tail;
+ tree rval = NULL_TREE;
+ /* An array of the base classes of BINFO. These will be built up in
+ breadth-first order, except where QFN prunes the search. */
+ varray_type bfs_bases;
- return rvals;
- }
- rval = NULL_TREE;
+ /* Start with enough room for ten base classes. That will be enough
+ for most hierarchies. */
+ VARRAY_TREE_INIT (bfs_bases, 10, "search_stack");
- if (name == ctor_identifier || name == dtor_identifier)
- {
- /* Don't allow lookups of constructors and destructors to go
- deeper than the first place we look. */
- return NULL_TREE;
- }
+ /* Put the first type into the stack. */
+ VARRAY_TREE (bfs_bases, 0) = binfo;
+ tail = 1;
- if (basetype_path == TYPE_BINFO (type))
+ for (head = 0; head < tail; ++head)
{
- basetype_chain = CLASSTYPE_BINFO_AS_LIST (type);
- my_friendly_assert (BINFO_INHERITANCE_CHAIN (basetype_path) == NULL_TREE,
- 980827);
- }
- else
- basetype_chain = build_expr_list (NULL_TREE, basetype_path);
+ int i;
+ int n_baselinks;
+ tree binfos;
- /* The ambiguity check relies upon breadth first searching. */
+ /* Pull the next type out of the queue. */
+ binfo = VARRAY_TREE (bfs_bases, head);
- search_stack = push_search_level (search_stack, &search_obstack);
- binfo = basetype_path;
- binfo_h = binfo;
-
- while (1)
- {
- tree binfos = BINFO_BASETYPES (binfo);
- int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
- int idx;
+ /* If this is the one we're looking for, we're done. */
+ rval = (*fn) (binfo, data);
+ if (rval)
+ break;
- /* Process and/or queue base types. */
+ /* Queue up the base types. */
+ 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);
- if (BINFO_FIELDS_MARKED (base_binfo) == 0)
+
+ if (qfn)
+ base_binfo = (*qfn) (base_binfo, data);
+
+ if (base_binfo)
{
- tree btypes;
-
- SET_BINFO_FIELDS_MARKED (base_binfo);
- btypes = scratch_tree_cons (NULL_TREE, base_binfo, basetype_chain);
- if (TREE_VIA_VIRTUAL (base_binfo))
- btypes = scratch_tree_cons (NULL_TREE,
- TYPE_BINFO (BINFO_TYPE (TREE_VEC_ELT (BINFO_BASETYPES (binfo_h), i))),
- btypes);
- else
- btypes = scratch_tree_cons (NULL_TREE,
- TREE_VEC_ELT (BINFO_BASETYPES (binfo_h), i),
- btypes);
- obstack_ptr_grow (&search_obstack, btypes);
- tail += 1;
- if (tail >= search_stack->limit)
- my_friendly_abort (99);
+ if (tail == VARRAY_SIZE (bfs_bases))
+ VARRAY_GROW (bfs_bases, 2 * VARRAY_SIZE (bfs_bases));
+ VARRAY_TREE (bfs_bases, tail) = base_binfo;
+ ++tail;
}
}
+ }
- /* Process head of queue, if one exists. */
- if (head >= tail)
- break;
-
- basetype_chain = search_stack->first[head++];
- binfo_h = TREE_VALUE (basetype_chain);
- basetype_chain = TREE_CHAIN (basetype_chain);
- basetype_path = TREE_VALUE (basetype_chain);
- if (TREE_CHAIN (basetype_chain))
- my_friendly_assert
- ((BINFO_INHERITANCE_CHAIN (basetype_path)
- == TREE_VALUE (TREE_CHAIN (basetype_chain)))
- /* We only approximate base info for partial instantiations. */
- || current_template_parms,
- 980827);
- else
- my_friendly_assert (BINFO_INHERITANCE_CHAIN (basetype_path)
- == NULL_TREE, 980827);
+ /* Clean up. */
+ VARRAY_FREE (bfs_bases);
- binfo = basetype_path;
- type = BINFO_TYPE (binfo);
+ return rval;
+}
- /* See if we can find NAME in TYPE. If RVAL is nonzero,
- and we do find NAME in TYPE, verify that such a second
- sighting is in fact valid. */
+/* Exactly like bfs_walk, except that a depth-first traversal is
+ performed, and PREFN is called in preorder, while POSTFN is called
+ in postorder. */
- idx = lookup_fnfields_here (type, name);
+static 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 *));
+ void *data;
+{
+ int i;
+ int n_baselinks;
+ tree binfos;
+ tree rval = NULL_TREE;
- if (idx >= 0 || (lookup_field_1 (type, name)!=NULL_TREE && !find_all))
- {
- if (rval_binfo && !find_all && hides (rval_binfo_h, binfo_h))
- {
- /* This is ok, the member found is in rval_binfo, not
- here (binfo). */
- }
- else if (rval_binfo==NULL_TREE || find_all || hides (binfo_h, rval_binfo_h))
- {
- /* This is ok, the member found is here (binfo), not in
- rval_binfo. */
- if (idx >= 0)
- {
- rval = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), idx);
- /* Note, rvals can only be previously set if find_all is
- true. */
- rvals = scratch_tree_cons (basetype_path, rval, rvals);
- if (TYPE_BINFO_BASETYPES (type)
- && CLASSTYPE_BASELINK_VEC (type))
- TREE_TYPE (rvals) = TREE_VEC_ELT (CLASSTYPE_BASELINK_VEC (type), idx);
- }
- else
- {
- /* Undo finding it before, as something else hides it. */
- rval = NULL_TREE;
- rvals = NULL_TREE;
- }
- rval_binfo = binfo;
- rval_binfo_h = binfo_h;
- }
- else
- {
- /* This is ambiguous. */
- errstr = "request for method `%D' is ambiguous";
- rvals = error_mark_node;
- break;
- }
- }
+ /* Call the pre-order walking function. */
+ if (prefn)
+ {
+ rval = (*prefn) (binfo, data);
+ if (rval)
+ return rval;
}
- {
- tree *tp = search_stack->first;
- tree *search_tail = tp + tail;
-
- while (tp < search_tail)
- {
- CLEAR_BINFO_FIELDS_MARKED (TREE_VALUE (TREE_CHAIN (*tp)));
- tp += 1;
- }
- }
- search_stack = pop_search_level (search_stack);
- if (errstr && protect)
+ /* Process the basetypes. */
+ binfos = BINFO_BASETYPES (binfo);
+ n_baselinks = binfos ? TREE_VEC_LENGTH (binfos): 0;
+ for (i = 0; i < n_baselinks; i++)
{
- cp_error (errstr, name);
- rvals = error_mark_node;
+ tree base_binfo = TREE_VEC_ELT (binfos, i);
+
+ if (qfn)
+ base_binfo = (*qfn) (base_binfo, data);
+
+ if (base_binfo)
+ {
+ rval = dfs_walk_real (base_binfo, prefn, postfn, qfn, data);
+ if (rval)
+ return rval;
+ }
}
- return rvals;
+ /* Call the post-order walking function. */
+ if (postfn)
+ rval = (*postfn) (binfo, data);
+
+ return rval;
}
-/* Look for a field or function 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. */
+/* Exactly like bfs_walk, except that a depth-first post-order traversal is
+ performed. */
tree
-lookup_member (xbasetype, name, protect, want_type)
- tree xbasetype, name;
- int protect, want_type;
+dfs_walk (binfo, fn, qfn, data)
+ tree binfo;
+ tree (*fn) PROTO((tree, void *));
+ tree (*qfn) PROTO((tree, void *));
+ void *data;
{
- tree ret, basetype_path;
-
- if (TREE_CODE (xbasetype) == TREE_VEC)
- basetype_path = xbasetype;
- else if (IS_AGGR_TYPE_CODE (TREE_CODE (xbasetype)))
- {
- basetype_path = TYPE_BINFO (xbasetype);
- my_friendly_assert (BINFO_INHERITANCE_CHAIN (basetype_path)
- == NULL_TREE, 980827);
- }
- else
- my_friendly_abort (97);
-
- ret = lookup_field (basetype_path, name, protect, want_type);
- if (! ret && ! want_type)
- ret = lookup_fnfields (basetype_path, name, protect);
- return ret;
+ return dfs_walk_real (binfo, 0, fn, qfn, data);
}
-\f
-/* BREADTH-FIRST SEARCH ROUTINES. */
-/* Search a multiple inheritance hierarchy by breadth-first search.
+struct gvnt_info
+{
+ /* The name of the function we are looking for. */
+ tree name;
+ /* The overloaded functions we have found. */
+ tree fields;
+};
- BINFO is an aggregate type, possibly in a multiple-inheritance hierarchy.
- TESTFN is a function, which, if true, means that our condition has been met,
- and its return value should be returned.
- QFN, if non-NULL, is a predicate dictating whether the type should
- even be queued. */
+/* Called from get_virtuals_named_this via bfs_walk. */
static tree
-breadth_first_search (binfo, testfn, qfn)
+get_virtuals_named_this_r (binfo, data)
tree binfo;
- tree (*testfn) PROTO((tree));
- int (*qfn) PROTO((tree));
+ void *data;
{
- int head = 0, tail = 0;
- tree rval = NULL_TREE;
-
- search_stack = push_search_level (search_stack, &search_obstack);
-
- SET_BINFO_MARKED (binfo);
- obstack_ptr_grow (&search_obstack, binfo);
- ++tail;
-
- while (1)
- {
- tree binfos = BINFO_BASETYPES (binfo);
- int n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
- int i;
-
- /* Process and/or queue base types. */
- for (i = 0; i < n_baselinks; i++)
- {
- tree base_binfo = TREE_VEC_ELT (binfos, i);
+ struct gvnt_info *gvnti = (struct gvnt_info *) data;
+ tree type = BINFO_TYPE (binfo);
+ int idx;
- if (BINFO_MARKED (base_binfo) == 0
- && (qfn == 0 || (*qfn) (base_binfo)))
- {
- SET_BINFO_MARKED (base_binfo);
- obstack_ptr_grow (&search_obstack, base_binfo);
- ++tail;
- if (tail >= search_stack->limit)
- my_friendly_abort (100);
- }
- }
- /* Process head of queue, if one exists. */
- if (head >= tail)
- {
- rval = 0;
- break;
- }
+ idx = lookup_fnfields_here (BINFO_TYPE (binfo), gvnti->name);
+ if (idx >= 0)
+ gvnti->fields
+ = tree_cons (binfo,
+ TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), idx),
+ gvnti->fields);
- binfo = search_stack->first[head++];
- if ((rval = (*testfn) (binfo)))
- break;
- }
- {
- tree *tp = search_stack->first;
- tree *search_tail = tp + tail;
- while (tp < search_tail)
- {
- tree binfo = *tp++;
- CLEAR_BINFO_MARKED (binfo);
- }
- }
-
- search_stack = pop_search_level (search_stack);
- return rval;
+ return NULL_TREE;
}
-/* Functions to use in breadth first searches. */
-typedef tree (*pfi) PROTO((tree));
-
-static tree declarator;
+/* Return the virtual functions with the indicated NAME in the type
+ indicated by BINFO. The result is a TREE_LIST whose TREE_PURPOSE
+ indicates the base class from which the TREE_VALUE (an OVERLOAD or
+ just a FUNCTION_DECL) originated. */
static tree
-get_virtuals_named_this (binfo)
+get_virtuals_named_this (binfo, name)
tree binfo;
+ tree name;
{
+ struct gvnt_info gvnti;
tree fields;
- fields = lookup_fnfields (binfo, declarator, -1);
- /* fields cannot be error_mark_node */
+ gvnti.name = name;
+ gvnti.fields = NULL_TREE;
- if (fields == 0)
- return 0;
+ bfs_walk (binfo, get_virtuals_named_this_r, 0, &gvnti);
/* Get to the function decls, and return the first virtual function
with this name, if there is one. */
- while (fields)
+ for (fields = gvnti.fields; fields; fields = next_baselink (fields))
{
tree fndecl;
for (fndecl = TREE_VALUE (fields); fndecl; fndecl = OVL_NEXT (fndecl))
if (DECL_VINDEX (OVL_CURRENT (fndecl)))
return fields;
- fields = next_baselink (fields);
}
return NULL_TREE;
}
static tree
-get_virtual_destructor (binfo)
+get_virtual_destructor (binfo, data)
tree binfo;
+ void *data ATTRIBUTE_UNUSED;
{
tree type = BINFO_TYPE (binfo);
if (TYPE_HAS_DESTRUCTOR (type)
return 0;
}
-static int
-tree_has_any_destructor_p (binfo)
+static tree
+tree_has_any_destructor_p (binfo, data)
tree binfo;
+ void *data ATTRIBUTE_UNUSED;
{
tree type = BINFO_TYPE (binfo);
- return TYPE_NEEDS_DESTRUCTOR (type);
+ return TYPE_NEEDS_DESTRUCTOR (type) ? binfo : NULL_TREE;
}
/* Returns > 0 if a function with type DRETTYPE overriding a function
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_CLASS_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:
/* Breadth first search routines start searching basetypes
of TYPE, so we must perform first ply of search here. */
if (dtorp)
- {
- return breadth_first_search (binfo,
- get_virtual_destructor,
- tree_has_any_destructor_p);
- }
+ return bfs_walk (binfo, get_virtual_destructor,
+ tree_has_any_destructor_p, 0);
else
{
tree drettype, dtypes, btypes, instptr_type;
- tree basetype = DECL_CLASS_CONTEXT (fndecl);
tree baselink, best = NULL_TREE;
- tree name = DECL_ASSEMBLER_NAME (fndecl);
-
- declarator = DECL_NAME (fndecl);
+ tree declarator = DECL_NAME (fndecl);
if (IDENTIFIER_VIRTUAL_P (declarator) == 0)
return NULL_TREE;
- baselink = get_virtuals_named_this (binfo);
+ baselink = get_virtuals_named_this (binfo, declarator);
if (baselink == NULL_TREE)
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);
- }
- break;
+ check_final_overrider (fndecl, tmp);
+
+ /* FNDECL overrides this function. We continue to
+ check all the other functions in order to catch
+ errors; it might be that in some other baseclass
+ a virtual function was declared with the same
+ parameter types, but a different return type. */
+ best = tmp;
}
}
- /* If not at the end */
- if (tmps)
- {
- best = tmp;
- break;
- }
}
return best;
}
}
-/* 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 = CLASSTYPE_ABSTRACT_VIRTUALS (type);
+ tree 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))
+ /* Mark the TYPE_BINFO hierarchy. */
+ dfs_walk (TYPE_BINFO (type), dfs_mark_primary_bases,
+ dfs_skip_nonprimary_vbases_unmarkedp, type);
+
+ /* Now go through the virtual base classes. Any that are not
+ already primary will need to be allocated in TYPE, and so we need
+ to mark their primary bases. */
+ for (vbase = CLASSTYPE_VBASECLASSES (type);
+ vbase;
+ vbase = TREE_CHAIN (vbase))
{
- tree virtuals = BINFO_VIRTUALS (vbases);
+ if (BINFO_VBASE_PRIMARY_P (vbase))
+ /* This virtual base was already included in the hierarchy, so
+ there's nothing to do here. */
+ continue;
- skip_rtti_stuff (&virtuals);
+ /* 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;
- 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);
- }
+ /* Now, walk its bases. */
+ dfs_walk (vbase, dfs_mark_primary_bases,
+ dfs_skip_nonprimary_vbases_unmarkedp, type);
+
+ /* VBASE wasn't really primary. */
+ BINFO_PRIMARY_MARKED_P (vbase) = 0;
+ /* And we don't want to allow it to *become* primary if it is a
+ base of some subsequent base class. */
+ SET_BINFO_VBASE_MARKED (vbase);
+ }
+
+ /* Clear the VBASE_MARKED bits we set above. */
+ for (vbase = CLASSTYPE_VBASECLASSES (type);
+ vbase;
+ vbase = TREE_CHAIN (vbase))
+ CLEAR_BINFO_VBASE_MARKED (vbase);
+}
+
+/* If BINFO is a non-primary virtual baseclass (in the hierarchy
+ dominated by TYPE), and no primary copy appears anywhere in the
+ hierarchy, return the shared copy. If a primary copy appears
+ elsewhere, return NULL_TREE. Otherwise, return BINFO itself; it is
+ either a non-virtual base or a primary virtual base. */
+
+static tree
+get_shared_vbase_if_not_primary (binfo, type)
+ tree binfo;
+ tree type;
+{
+ if (TREE_VIA_VIRTUAL (binfo) && !BINFO_PRIMARY_MARKED_P (binfo))
+ {
+ /* This is a non-primary virtual base. If there is no primary
+ version, get the shared version. */
+ binfo = BINFO_FOR_VBASE (BINFO_TYPE (binfo), type);
+ if (BINFO_VBASE_PRIMARY_P (binfo))
+ return NULL_TREE;
}
- return 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);
+ tree type = (tree) data;
- search_stack = push_search_level (search_stack, &search_obstack);
+ if (TREE_CODE (type) == TREE_LIST)
+ type = TREE_PURPOSE (type);
+ binfo = get_shared_vbase_if_not_primary (binfo, type);
+ return binfo ? unmarkedp (binfo, NULL) : NULL_TREE;
+}
- while (1)
- {
- tree binfos = BINFO_BASETYPES (binfo);
- int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+/* Like dfs_unmarked_real_bases_queue_p but walks only into things
+ that are marked, rather than unmarked. */
- /* 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;
- }
+tree
+dfs_marked_real_bases_queue_p (binfo, data)
+ tree binfo;
+ void *data;
+{
+ tree type = (tree) data;
- dont_queue:
- /* Process head of queue, if one exists. */
- if (head >= tail)
- break;
+ if (TREE_CODE (type) == TREE_LIST)
+ type = TREE_PURPOSE (type);
+ binfo = get_shared_vbase_if_not_primary (binfo, type);
+ return binfo ? markedp (binfo, NULL) : NULL_TREE;
+}
- basetypes = search_stack->first[head++];
- binfo = TREE_VALUE (basetypes);
- type = BINFO_TYPE (binfo);
- idx = lookup_fnfields_1 (type, name);
- if (idx >= 0)
+/* 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;
+
+ /* 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);
-}
-
-/* The main function which implements depth first search.
-
- This routine has to remember the path it walked up, when
- dfs_init_vbase_pointers is the work function, as otherwise there
- would be no record. */
-
-static void
-dfs_walk (binfo, fn, qfn)
- tree binfo;
- void (*fn) PROTO((tree));
- int (*qfn) PROTO((tree));
-{
- tree binfos = BINFO_BASETYPES (binfo);
- int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
-
- 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 (qfn == 0 || (*qfn)(base_binfo))
- {
- if (TREE_CODE (BINFO_TYPE (base_binfo)) == TEMPLATE_TYPE_PARM
- || TREE_CODE (BINFO_TYPE (base_binfo)) == TEMPLATE_TEMPLATE_PARM)
- /* Pass */;
- else if (fn == dfs_init_vbase_pointers)
- {
- /* When traversing an arbitrary MI hierarchy, we need to keep
- a record of the path we took to get down to the final base
- type, as otherwise there would be no record of it, and just
- trying to blindly convert at the bottom would be ambiguous.
+ 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);
+ }
- The easiest way is to do the conversions one step at a time,
- as we know we want the immediate base class at each step.
+ my_friendly_abort (19990607);
- The only special trick to converting one step at a time,
- is that when we hit the last virtual base class, we must
- use the SLOT value for it, and not use the normal convert
- routine. We use the last virtual base class, as in our
- implementation, we have pointers to all virtual base
- classes in the base object. */
+ /* NOTREACHED */
+ return NULL_TREE;
+}
- tree saved_vbase_decl_ptr_intermediate
- = vbase_decl_ptr_intermediate;
+tree
+markedp (binfo, data)
+ tree binfo;
+ void *data ATTRIBUTE_UNUSED;
+{
+ return BINFO_MARKED (binfo) ? binfo : NULL_TREE;
+}
- if (TREE_VIA_VIRTUAL (base_binfo))
- {
- /* No need for the conversion here, as we know it is the
- right type. */
- vbase_decl_ptr_intermediate
- = CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (base_binfo));
- }
- else
- {
- vbase_decl_ptr_intermediate
- = convert_pointer_to_single_level (BINFO_TYPE (base_binfo),
- vbase_decl_ptr_intermediate);
- }
+tree
+unmarkedp (binfo, data)
+ tree binfo;
+ void *data ATTRIBUTE_UNUSED;
+{
+ return !BINFO_MARKED (binfo) ? binfo : NULL_TREE;
+}
- dfs_walk (base_binfo, fn, qfn);
+static tree
+marked_vtable_pathp (binfo, data)
+ tree binfo;
+ void *data ATTRIBUTE_UNUSED;
+{
+ return BINFO_VTABLE_PATH_MARKED (binfo) ? binfo : NULL_TREE;
+}
- vbase_decl_ptr_intermediate = saved_vbase_decl_ptr_intermediate;
- }
- else
- dfs_walk (base_binfo, fn, qfn);
- }
- }
+static tree
+unmarked_vtable_pathp (binfo, data)
+ tree binfo;
+ void *data ATTRIBUTE_UNUSED;
+{
+ return !BINFO_VTABLE_PATH_MARKED (binfo) ? binfo : NULL_TREE;
+}
- fn (binfo);
+static tree
+marked_new_vtablep (binfo, data)
+ tree binfo;
+ void *data ATTRIBUTE_UNUSED;
+{
+ return BINFO_NEW_VTABLE_MARKED (binfo) ? binfo : NULL_TREE;
}
-/* 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
+unmarked_new_vtablep (binfo, data)
+ tree binfo;
+ void *data ATTRIBUTE_UNUSED;
+{
+ return !BINFO_NEW_VTABLE_MARKED (binfo) ? binfo : NULL_TREE;
+}
static tree
-dfs_search (binfo, fn, start)
- tree binfo, start;
- tree (*fn) PROTO((tree));
+marked_pushdecls_p (binfo, data)
+ tree binfo;
+ void *data ATTRIBUTE_UNUSED;
{
- tree binfos = BINFO_BASETYPES (binfo);
- int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
- tree retval;
-
- for (i = 0; i < n_baselinks; 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;
- }
- }
-
- return fn (binfo);
+ return (CLASS_TYPE_P (BINFO_TYPE (binfo))
+ && BINFO_PUSHDECLS_MARKED (binfo)) ? binfo : NULL_TREE;
}
-static int markedp (binfo) tree binfo;
-{ return BINFO_MARKED (binfo); }
-static int unmarkedp (binfo) tree binfo;
-{ return BINFO_MARKED (binfo) == 0; }
-
-#if 0
-static int bfs_markedp (binfo, i) tree binfo; int i;
-{ return BINFO_MARKED (BINFO_BASETYPE (binfo, i)); }
-static int bfs_unmarkedp (binfo, i) tree binfo; int i;
-{ return BINFO_MARKED (BINFO_BASETYPE (binfo, i)) == 0; }
-static int bfs_marked_vtable_pathp (binfo, i) tree binfo; int i;
-{ return BINFO_VTABLE_PATH_MARKED (BINFO_BASETYPE (binfo, i)); }
-static int bfs_unmarked_vtable_pathp (binfo, i) tree binfo; int i;
-{ return BINFO_VTABLE_PATH_MARKED (BINFO_BASETYPE (binfo, i)) == 0; }
-static int bfs_marked_new_vtablep (binfo, i) tree binfo; int i;
-{ return BINFO_NEW_VTABLE_MARKED (BINFO_BASETYPE (binfo, i)); }
-static int bfs_unmarked_new_vtablep (binfo, i) tree binfo; int i;
-{ return BINFO_NEW_VTABLE_MARKED (BINFO_BASETYPE (binfo, i)) == 0; }
-#endif
-
-static int marked_vtable_pathp (binfo) tree binfo;
-{ return BINFO_VTABLE_PATH_MARKED (binfo); }
-static int unmarked_vtable_pathp (binfo) tree binfo;
-{ return BINFO_VTABLE_PATH_MARKED (binfo) == 0; }
-static int marked_new_vtablep (binfo) tree binfo;
-{ return BINFO_NEW_VTABLE_MARKED (binfo); }
-static int unmarked_new_vtablep (binfo) tree binfo;
-{ return BINFO_NEW_VTABLE_MARKED (binfo) == 0; }
-static int marked_pushdecls_p (binfo) tree binfo;
-{ return BINFO_PUSHDECLS_MARKED (binfo); }
-static int unmarked_pushdecls_p (binfo) tree binfo;
-{ return BINFO_PUSHDECLS_MARKED (binfo) == 0; }
+static tree
+unmarked_pushdecls_p (binfo, data)
+ tree binfo;
+ void *data ATTRIBUTE_UNUSED;
+{
+ 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 int dfs_debug_unmarkedp (binfo) tree binfo;
-{ return CLASSTYPE_DEBUG_REQUESTED (BINFO_TYPE (binfo)) == 0; }
+static tree
+dfs_debug_unmarkedp (binfo, data)
+ tree binfo;
+ void *data ATTRIBUTE_UNUSED;
+{
+ 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
{ SET_BINFO_MARKED (binfo); }
#endif
-static void
-dfs_unmark (binfo) tree binfo;
-{ CLEAR_BINFO_MARKED (binfo); }
+tree
+dfs_unmark (binfo, data)
+ tree binfo;
+ void *data ATTRIBUTE_UNUSED;
+{
+ CLEAR_BINFO_MARKED (binfo);
+ return NULL_TREE;
+}
+
+/* Clear both BINFO_MARKED and BINFO_VBASE_MARKED. */
+
+tree
+dfs_vbase_unmark (binfo, data)
+ tree binfo;
+ void *data ATTRIBUTE_UNUSED;
+{
+ CLEAR_BINFO_VBASE_MARKED (binfo);
+ return dfs_unmark (binfo, data);
+}
#if 0
static void
static void
dfs_clear_search_slot (binfo) tree binfo;
{ CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (binfo)) = 0; }
-#endif
-static void
-dfs_debug_mark (binfo)
+/* 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;
+ void *data ATTRIBUTE_UNUSED;
{
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;
-
/* 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;
+ return NULL_TREE;
+
+ /* If the class has virtual functions, we'll emit the debug info
+ with the vtable. */
+ if (TYPE_POLYMORPHIC_P (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;
- }
- methods = TREE_CHAIN (methods);
- }
- }
/* 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;
rest_of_type_compilation (t, toplevel_bindings_p ());
+
+ return NULL_TREE;
}
+#endif
\f
-/* Attach to the type of the virtual base class, the pointer to the
- virtual base class, given the global pointer vbase_decl_ptr.
+struct vbase_info
+{
+ tree decl_ptr;
+ tree inits;
+ tree vbase_types;
+};
- We use the global vbase_types. ICK! */
+/* Attach to the type of the virtual base class, the pointer to the
+ virtual base class. */
-static void
-dfs_find_vbases (binfo)
+static tree
+dfs_find_vbases (binfo, data)
tree binfo;
+ void *data;
{
+ struct vbase_info *vi = (struct vbase_info *) data;
tree binfos = BINFO_BASETYPES (binfo);
int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
&& CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (base_binfo)) == 0)
{
tree vbase = BINFO_TYPE (base_binfo);
- tree binfo = binfo_member (vbase, vbase_types);
+ tree binfo = binfo_member (vbase, vi->vbase_types);
CLASSTYPE_SEARCH_SLOT (vbase)
= build (PLUS_EXPR, build_pointer_type (vbase),
- vbase_decl_ptr, BINFO_OFFSET (binfo));
+ vi->decl_ptr, BINFO_OFFSET (binfo));
}
}
SET_BINFO_VTABLE_PATH_MARKED (binfo);
SET_BINFO_NEW_VTABLE_MARKED (binfo);
+
+ return NULL_TREE;
}
-static void
-dfs_init_vbase_pointers (binfo)
+static tree
+dfs_init_vbase_pointers (binfo, data)
tree binfo;
+ void *data;
{
+ 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)))
+ if (BINFO_INHERITANCE_CHAIN (binfo))
+ {
+ this_vbase_ptr = TREE_CHAIN (BINFO_INHERITANCE_CHAIN (binfo));
+ if (TREE_VIA_VIRTUAL (binfo))
+ this_vbase_ptr = CLASSTYPE_SEARCH_SLOT (type);
+ else
+ this_vbase_ptr = convert_pointer_to_single_level (type,
+ this_vbase_ptr);
+ TREE_CHAIN (binfo) = this_vbase_ptr;
+ }
+ 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);
-#endif
if (fields == NULL_TREE
|| DECL_NAME (fields) == NULL_TREE
|| ! VBASE_NAME_P (DECL_NAME (fields)))
- return;
-
- this_vbase_ptr = vbase_decl_ptr_intermediate;
+ return NULL_TREE;
- if (build_pointer_type (type) != TYPE_MAIN_VARIANT (TREE_TYPE (this_vbase_ptr)))
+ if (build_pointer_type (type)
+ != TYPE_MAIN_VARIANT (TREE_TYPE (this_vbase_ptr)))
my_friendly_abort (125);
- while (fields && DECL_NAME (fields)
- && VBASE_NAME_P (DECL_NAME (fields)))
+ while (fields && DECL_NAME (fields) && VBASE_NAME_P (DECL_NAME (fields)))
{
tree ref = build (COMPONENT_REF, TREE_TYPE (fields),
build_indirect_ref (this_vbase_ptr, NULL_PTR), fields);
tree init = CLASSTYPE_SEARCH_SLOT (TREE_TYPE (TREE_TYPE (fields)));
- vbase_init_result = tree_cons (binfo_member (TREE_TYPE (TREE_TYPE (fields)),
- vbase_types),
- build_modify_expr (ref, NOP_EXPR, init),
- vbase_init_result);
+ vi->inits = tree_cons (binfo_member (TREE_TYPE (TREE_TYPE (fields)),
+ vi->vbase_types),
+ build_modify_expr (ref, NOP_EXPR, init),
+ vi->inits);
fields = TREE_CHAIN (fields);
}
+
+ return NULL_TREE;
}
/* Sometimes this needs to clear both VTABLE_PATH and NEW_VTABLE. Other
times, just NEW_VTABLE, but optimizer should make both with equal
efficiency (though it does not currently). */
-static void
-dfs_clear_vbase_slots (binfo)
+static tree
+dfs_clear_vbase_slots (binfo, data)
tree binfo;
+ void *data ATTRIBUTE_UNUSED;
{
tree type = BINFO_TYPE (binfo);
CLASSTYPE_SEARCH_SLOT (type) = 0;
CLEAR_BINFO_VTABLE_PATH_MARKED (binfo);
CLEAR_BINFO_NEW_VTABLE_MARKED (binfo);
+ return NULL_TREE;
}
tree
{
if (TYPE_USES_VIRTUAL_BASECLASSES (type))
{
+ struct vbase_info vi;
int old_flag = flag_this_is_variable;
tree binfo = TYPE_BINFO (type);
flag_this_is_variable = -2;
- vbase_types = CLASSTYPE_VBASECLASSES (type);
- vbase_decl_ptr = vbase_decl_ptr_intermediate = decl_ptr;
- vbase_init_result = NULL_TREE;
- dfs_walk (binfo, dfs_find_vbases, unmarked_vtable_pathp);
- dfs_walk (binfo, dfs_init_vbase_pointers, marked_vtable_pathp);
- dfs_walk (binfo, dfs_clear_vbase_slots, marked_new_vtablep);
+
+ /* Find all the virtual base classes, marking them for later
+ initialization. */
+ vi.decl_ptr = decl_ptr;
+ vi.vbase_types = CLASSTYPE_VBASECLASSES (type);
+ vi.inits = NULL_TREE;
+
+ dfs_walk (binfo, dfs_find_vbases, unmarked_vtable_pathp, &vi);
+
+ /* Build up a list of the initializers. */
+ TREE_CHAIN (binfo) = decl_ptr;
+ dfs_walk_real (binfo,
+ dfs_init_vbase_pointers, 0,
+ marked_vtable_pathp,
+ &vi);
+
+ dfs_walk (binfo, dfs_clear_vbase_slots, marked_new_vtablep, 0);
flag_this_is_variable = old_flag;
- return vbase_init_result;
+ return vi.inits;
}
return 0;
}
/* Not sure if checking path == vbase is necessary here, but just in
case it is. */
if (TREE_VIA_VIRTUAL (path) || path == vbase)
- return binfo_member (BINFO_TYPE (path), CLASSTYPE_VBASECLASSES (t));
+ return BINFO_FOR_VBASE (BINFO_TYPE (path), t);
path = BINFO_INHERITANCE_CHAIN (path);
}
}
vbase_offsets)
tree binfo, addr, orig_addr, vbase, vbase_addr, t, *vbase_offsets;
{
- tree virtuals = BINFO_VIRTUALS (binfo);
+ tree virtuals;
tree vc;
tree delta;
unsigned HOST_WIDE_INT n;
*vbase_offsets = delta;
}
- n = skip_rtti_stuff (&virtuals);
+ 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;
}
}
-/* 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_offsets;
+ tree addr;
+
+ vbase_offsets = NULL_TREE;
+ addr = convert_pointer_to_vbase (TREE_TYPE (vbases), decl_ptr);
+ fixup_virtual_upcast_offsets (vbases,
+ TYPE_BINFO (BINFO_TYPE (vbases)),
+ 1, 0, addr, decl_ptr,
+ type, vbases, &vbase_offsets);
+ }
+ }
- 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.
+ /* Close out the if-statement. */
+ finish_then_clause (if_stmt);
+ finish_if_stmt ();
+}
- We setup and use the globals: vbase_decl_ptr, vbase_types
- ICK! */
+/* 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);
- vbase_types = vbases;
- vbase_decl_ptr = true_exp ? build_unary_op (ADDR_EXPR, true_exp, 0) : decl_ptr;
-
- dfs_walk (binfo, dfs_find_vbases, unmarked_new_vtablep);
-
- /* Initialized with vtables of type TYPE. */
- for (; vbases; vbases = TREE_CHAIN (vbases))
- {
- tree addr;
-
- addr = convert_pointer_to_vbase (TREE_TYPE (vbases), vbase_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, vbase_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 ();
- }
+ struct vbase_info vi;
+ vi.decl_ptr = decl_ptr;
+ vi.vbase_types = vbases;
- dfs_walk (binfo, dfs_clear_vbase_slots, marked_new_vtablep);
+ dfs_walk (binfo, dfs_find_vbases, unmarked_new_vtablep, &vi);
+ fixup_all_virtual_upcast_offsets (type, vi.decl_ptr);
+ dfs_walk (binfo, dfs_clear_vbase_slots, marked_new_vtablep, 0);
}
}
This adds type to the vbase_types list in reverse dfs order.
Ordering is very important, so don't change it. */
-static void
-dfs_get_vbase_types (binfo)
+static tree
+dfs_get_vbase_types (binfo, data)
tree binfo;
+ void *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;
}
-/* get a list of virtual base classes in dfs order. */
+/* Set CLASSTYPE_VBASECLASSES for TYPE. */
-tree
+void
get_vbase_types (type)
tree type;
{
- tree vbases;
- tree binfo;
-
- binfo = TYPE_BINFO (type);
- vbase_types = NULL_TREE;
- dfs_walk (binfo, dfs_get_vbase_types, unmarkedp);
- dfs_walk (binfo, dfs_unmark, markedp);
+ CLASSTYPE_VBASECLASSES (type) = NULL_TREE;
+ dfs_walk (TYPE_BINFO (type), dfs_get_vbase_types, unmarkedp, type);
/* Rely upon the reverse dfs ordering from dfs_get_vbase_types, and now
reverse it so that we get normal dfs ordering. */
- vbase_types = nreverse (vbase_types);
+ CLASSTYPE_VBASECLASSES (type) = nreverse (CLASSTYPE_VBASECLASSES (type));
+ dfs_walk (TYPE_BINFO (type), dfs_vbase_unmark, markedp, 0);
+}
+\f
+/* Debug info for C++ classes can get very large; try to avoid
+ emitting it everywhere.
+
+ Note that this optimization wins even when the target supports
+ BINCL (if only slightly), and reduces the amount of work for the
+ linker. */
- /* unmark marked vbases */
- for (vbases = vbase_types; vbases; vbases = TREE_CHAIN (vbases))
- CLEAR_BINFO_VBASE_MARKED (vbases);
+void
+maybe_suppress_debug_info (t)
+ tree t;
+{
+ /* We can't do the usual TYPE_DECL_SUPPRESS_DEBUG thing with DWARF, which
+ does not support name references between translation units. It supports
+ symbolic references between translation units, but only within a single
+ executable or shared library.
+
+ For DWARF 2, we handle TYPE_DECL_SUPPRESS_DEBUG by pretending
+ that the type was never defined, so we only get the members we
+ actually define. */
+ if (write_symbols == DWARF_DEBUG || write_symbols == NO_DEBUG)
+ return;
+
+ /* We might have set this earlier in cp_finish_decl. */
+ TYPE_DECL_SUPPRESS_DEBUG (TYPE_MAIN_DECL (t)) = 0;
+
+ /* If we already know how we're handling this class, handle debug info
+ the same way. */
+ if (CLASSTYPE_INTERFACE_ONLY (t))
+ TYPE_DECL_SUPPRESS_DEBUG (TYPE_MAIN_DECL (t)) = 1;
+ else if (CLASSTYPE_INTERFACE_KNOWN (t))
+ /* Don't set it. */;
+ /* If the class has virtual functions, write out the debug info
+ along with the vtable. */
+ else if (TYPE_POLYMORPHIC_P (t))
+ TYPE_DECL_SUPPRESS_DEBUG (TYPE_MAIN_DECL (t)) = 1;
- return vbase_types;
+ /* Otherwise, just emit the debug info normally. */
}
-\f
+
+#if 0
+/* Keep this code around in case we later want to control debug info
+ based on whether a type is "used". Currently, we only suppress debug
+ info if we can emit it with the vtable. jason 1999-11-11) */
+
/* If we want debug info for a type TYPE, make sure all its base types
are also marked as being potentially interesting. This avoids
the problem of not writing any debug info for intermediate basetypes
/* We can't go looking for the base types and fields just yet. */
return;
- /* We can't do the TYPE_DECL_SUPPRESS_DEBUG thing with DWARF, which
- does not support name references between translation units. Well, we
- could, but that would mean putting global labels in the debug output
- before each exported type and each of its functions and static data
- members. */
- if (write_symbols == DWARF_DEBUG || write_symbols == DWARF2_DEBUG)
+ /* 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);
+ dfs_walk (TYPE_BINFO (type), dfs_debug_mark, dfs_debug_unmarkedp, 0);
for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
{
tree ttype;
if (TREE_CODE (field) == FIELD_DECL
&& IS_AGGR_TYPE (ttype = target_type (TREE_TYPE (field)))
- && dfs_debug_unmarkedp (TYPE_BINFO (ttype)))
+ && dfs_debug_unmarkedp (TYPE_BINFO (ttype), 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. */
{
for (; binfo; binfo = BINFO_INHERITANCE_CHAIN (binfo))
{
- if (TREE_TYPE (binfo) == current_class_type)
+ if (currently_open_class (TREE_TYPE (binfo)))
break;
if (uses_template_parms (TREE_TYPE (binfo)))
return 1;
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 void
-dfs_pushdecls (binfo)
- tree binfo;
+setup_class_bindings (name, type_binding_p)
+ tree name;
+ int type_binding_p;
{
- 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)));
- 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 void
-dfs_compress_decls (binfo)
+static tree
+dfs_push_decls (binfo, data)
tree binfo;
+ 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;
}
/* When entering the scope of a class, we cache all of the
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. */
- dfs_walk (TYPE_BINFO (type), dfs_pushdecls, unmarked_pushdecls_p);
-
- /* 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);
-
- /* 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 ();
+ /* Enter type declarations and mark. */
+ dfs_walk (TYPE_BINFO (type), dfs_push_type_decls, unmarked_pushdecls_p, 0);
- 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. */
-static void
-dfs_unuse_fields (binfo)
+static tree
+dfs_unuse_fields (binfo, data)
tree binfo;
+ void *data ATTRIBUTE_UNUSED;
{
tree type = TREE_TYPE (binfo);
tree fields;
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));
}
+
+ return NULL_TREE;
}
void
unuse_fields (type)
tree type;
{
- dfs_walk (TYPE_BINFO (type), dfs_unuse_fields, unmarkedp);
+ dfs_walk (TYPE_BINFO (type), dfs_unuse_fields, unmarkedp, 0);
}
void
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 conversions;
static tree
-add_conversions (binfo)
+add_conversions (binfo, data)
tree binfo;
+ void *data;
{
int i;
tree method_vec = CLASSTYPE_METHOD_VEC (BINFO_TYPE (binfo));
- tree name = NULL_TREE;
+ 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);
+ tree name;
if (!tmp || ! DECL_CONV_FN_P (OVL_CURRENT (tmp)))
break;
- /* We don't want to mark 'name' until we've seen all the overloads
- in this class; we could be overloading on the quals of 'this'. */
- if (name && name != DECL_NAME (tmp))
- {
- IDENTIFIER_MARKED (name) = 1;
- name = NULL_TREE;
- }
+ name = DECL_NAME (OVL_CURRENT (tmp));
/* Make sure we don't already have this conversion. */
- if (! IDENTIFIER_MARKED (DECL_NAME (tmp)))
+ if (! IDENTIFIER_MARKED (name))
{
- conversions = scratch_tree_cons (binfo, tmp, conversions);
- name = DECL_NAME (tmp);
+ *conversions = tree_cons (binfo, tmp, *conversions);
+ IDENTIFIER_MARKED (name) = 1;
}
}
-
- if (name)
- 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;
{
tree t;
-
- conversions = NULL_TREE;
+ tree conversions = NULL_TREE;
if (TYPE_SIZE (type))
- breadth_first_search (TYPE_BINFO (type), add_conversions, 0);
+ bfs_walk (TYPE_BINFO (type), add_conversions, 0, &conversions);
for (t = conversions; t; t = TREE_CHAIN (t))
- IDENTIFIER_MARKED (DECL_NAME (TREE_VALUE (t))) = 0;
+ IDENTIFIER_MARKED (DECL_NAME (OVL_CURRENT (TREE_VALUE (t)))) = 0;
return conversions;
}
-/* Subroutine of get_template_base. */
-
-static tree
-get_template_base_recursive (binfo, rval, template, via_virtual)
- tree binfo, template, rval;
- int via_virtual;
-{
- tree binfos;
- int i, n_baselinks;
- tree type = BINFO_TYPE (binfo);
-
- if (CLASSTYPE_TEMPLATE_INFO (type)
- && CLASSTYPE_TI_TEMPLATE (type) == template)
- {
- if (rval == NULL_TREE || rval == type)
- return type;
- else
- return error_mark_node;
- }
-
- binfos = BINFO_BASETYPES (binfo);
- n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
-
- /* Process base types. */
- for (i = 0; i < n_baselinks; i++)
- {
- tree base_binfo = TREE_VEC_ELT (binfos, i);
-
- /* Find any specific instance of a virtual base, when searching with
- a binfo... */
- if (BINFO_MARKED (base_binfo) == 0)
- {
- int this_virtual = via_virtual || TREE_VIA_VIRTUAL (base_binfo);
-
- /* When searching for a non-virtual, we cannot mark
- virtually found binfos. */
- if (! this_virtual)
- SET_BINFO_MARKED (base_binfo);
-
- rval = get_template_base_recursive
- (base_binfo, rval, template, this_virtual);
- if (rval == error_mark_node)
- return rval;
- }
- }
-
- return rval;
-}
-
-/* Given a class template TEMPLATE and a class type or binfo node BINFO,
- find the unique base type in BINFO that is an instance of TEMPLATE.
- If there are more than one, return error_mark_node. Used by unify. */
-
-tree
-get_template_base (template, binfo)
- register tree template, binfo;
+struct overlap_info
{
- tree type = NULL_TREE, rval;
-
- if (TREE_CODE (binfo) == TREE_VEC)
- type = BINFO_TYPE (binfo);
- else if (IS_AGGR_TYPE_CODE (TREE_CODE (binfo)))
- {
- type = complete_type (binfo);
- binfo = TYPE_BINFO (type);
- }
- else
- my_friendly_abort (92);
-
- if (CLASSTYPE_TEMPLATE_INFO (type)
- && CLASSTYPE_TI_TEMPLATE (type) == template)
- return type;
-
- rval = get_template_base_recursive (binfo, NULL_TREE, template, 0);
- dfs_walk (binfo, dfs_unmark, markedp);
-
- return rval;
-}
+ tree compare_type;
+ int found_overlap;
+};
/* Check whether the empty class indicated by EMPTY_BINFO is also present
at offset 0 in COMPARE_TYPE, and set found_overlap if so. */
-static tree compare_type;
-static int found_overlap;
-static void
-dfs_check_overlap (empty_binfo)
+static tree
+dfs_check_overlap (empty_binfo, data)
tree empty_binfo;
+ void *data;
{
+ struct overlap_info *oi = (struct overlap_info *) data;
tree binfo;
- for (binfo = TYPE_BINFO (compare_type); ; binfo = BINFO_BASETYPE (binfo, 0))
+ for (binfo = TYPE_BINFO (oi->compare_type);
+ ;
+ binfo = BINFO_BASETYPE (binfo, 0))
{
if (BINFO_TYPE (binfo) == BINFO_TYPE (empty_binfo))
{
- found_overlap = 1;
+ oi->found_overlap = 1;
break;
}
else if (BINFO_BASETYPES (binfo) == NULL_TREE)
break;
}
+
+ return NULL_TREE;
}
/* Trivial function to stop base traversal when we find something. */
-static int
-dfs_no_overlap_yet (t)
- tree t ATTRIBUTE_UNUSED;
+static tree
+dfs_no_overlap_yet (binfo, data)
+ tree binfo;
+ void *data;
{
- return found_overlap == 0;
+ struct overlap_info *oi = (struct overlap_info *) data;
+ return !oi->found_overlap ? binfo : NULL_TREE;
}
/* Returns nonzero if EMPTY_TYPE or any of its bases can also be found at
types_overlap_p (empty_type, next_type)
tree empty_type, next_type;
{
+ struct overlap_info oi;
+
if (! IS_AGGR_TYPE (next_type))
return 0;
- compare_type = next_type;
- found_overlap = 0;
- dfs_walk (TYPE_BINFO (empty_type), dfs_check_overlap, dfs_no_overlap_yet);
- return found_overlap;
+ oi.compare_type = next_type;
+ oi.found_overlap = 0;
+ dfs_walk (TYPE_BINFO (empty_type), dfs_check_overlap,
+ dfs_no_overlap_yet, &oi);
+ return oi.found_overlap;
}
-/* Passed to dfs_search by binfo_for_vtable; determine if bvtable comes
- from BINFO. */
+/* Given a vtable VAR, determine which binfo it comes from.
-static tree bvtable;
-static tree
-dfs_bfv_helper (binfo)
- tree binfo;
+ FIXME What about secondary vtables? */
+
+tree
+binfo_for_vtable (var)
+ tree var;
{
- if (BINFO_VTABLE (binfo) == bvtable)
- return binfo;
- return NULL_TREE;
+ tree binfo = TYPE_BINFO (DECL_CONTEXT (var));
+ tree binfos;
+ int i;
+
+ while (1)
+ {
+ binfos = BINFO_BASETYPES (binfo);
+ if (binfos == NULL_TREE)
+ break;
+
+ i = CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo));
+ if (i == -1)
+ break;
+
+ binfo = TREE_VEC_ELT (binfos, i);
+ }
+
+ return binfo;
}
-/* Given a vtable VARS, determine which binfo it comes from. */
+/* Returns 1 iff BINFO is from a direct or indirect virtual base. */
-tree
-binfo_for_vtable (vars)
- tree vars;
+int
+binfo_from_vbase (binfo)
+ tree binfo;
{
- bvtable = vars;
- return dfs_search (TYPE_BINFO (DECL_CONTEXT (vars)), dfs_bfv_helper,
- DECL_CONTEXT (vars));
+ for (; binfo; binfo = BINFO_INHERITANCE_CHAIN (binfo))
+ {
+ if (TREE_VIA_VIRTUAL (binfo))
+ return 1;
+ }
+ return 0;
}