/* Breadth-first and depth-first routines for
searching multiple-inheritance lattice for GNU C++.
- Copyright (C) 1987, 89, 92, 93, 94, 1995 Free Software Foundation, Inc.
+ Copyright (C) 1987, 89, 92-97, 1998 Free Software Foundation, Inc.
Contributed by Michael Tiemann (tiemann@cygnus.com)
This file is part of GNU CC.
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
-/* High-level class interface. */
+/* High-level class interface. */
#include "config.h"
+#include "system.h"
#include "tree.h"
-#include <stdio.h>
#include "cp-tree.h"
#include "obstack.h"
#include "flags.h"
#include "rtl.h"
#include "output.h"
+#include "toplev.h"
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
-void init_search ();
extern struct obstack *current_obstack;
extern tree abort_fndecl;
#include "stack.h"
/* Obstack used for remembering decision points of breadth-first. */
+
static struct obstack search_obstack;
/* Methods for pushing and popping objects to and from obstacks. */
+
struct stack_level *
push_stack_level (obstack, tp, size)
struct obstack *obstack;
#define search_level stack_level
static struct search_level *search_stack;
-static tree lookup_field_1 ();
-static int lookup_fnfields_1 ();
-static void dfs_walk ();
-static int markedp ();
-static void dfs_unmark ();
-static void dfs_init_vbase_pointers ();
+static tree get_abstract_virtuals_1 PROTO((tree, int, tree));
+static tree get_vbase_1 PROTO((tree, tree, unsigned int *));
+static tree convert_pointer_to_vbase PROTO((tree, tree));
+static tree lookup_field_1 PROTO((tree, tree));
+static tree convert_pointer_to_single_level PROTO((tree, tree));
+static int lookup_fnfields_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 int get_base_distance_recursive
+ PROTO((tree, int, int, int, int *, tree *, tree,
+ int, int *, int, int));
+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 int covariant_return_p 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, vbase_decl_ptr;
-static tree vbase_decl_ptr_intermediate;
+static tree vbase_decl_ptr_intermediate, vbase_decl_ptr;
static tree vbase_init_result;
/* Allocate a level of searching. */
+
static struct search_level *
push_search_level (stack, obstack)
struct stack_level *stack;
}
/* Discard a level of search allocation. */
+
static struct search_level *
pop_search_level (obstack)
struct stack_level *obstack;
return stack;
}
\f
-/* Search memoization. */
-struct type_level
-{
- struct stack_level base;
-
- /* First object allocated in obstack of entries. */
- char *entries;
-
- /* Number of types memoized in this context. */
- int len;
-
- /* Type being memoized; save this if we are saving
- memoized contexts. */
- tree type;
-};
-
-/* Obstack used for memoizing member and member function lookup. */
-
-static struct obstack type_obstack, type_obstack_entries;
-static struct type_level *type_stack;
static tree _vptr_name;
-/* Make things that look like tree nodes, but allocate them
- on type_obstack_entries. */
-static int my_tree_node_counter;
-static tree my_tree_cons (), my_build_string ();
-
-extern int flag_memoize_lookups, flag_save_memoized_contexts;
-
/* Variables for gathering statistics. */
-static int my_memoized_entry_counter;
-static int memoized_fast_finds[2], memoized_adds[2], memoized_fast_rejects[2];
-static int memoized_fields_searched[2];
+#ifdef GATHER_STATISTICS
static int n_fields_searched;
static int n_calls_lookup_field, n_calls_lookup_field_1;
static int n_calls_lookup_fnfields, n_calls_lookup_fnfields_1;
static int n_calls_get_base_type;
static int n_outer_fields_searched;
static int n_contexts_saved;
-
-/* Local variables to help save memoization contexts. */
-static tree prev_type_memoized;
-static struct type_level *prev_type_stack;
+#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;
-
-/* Allocate a level of type memoization context. */
-static struct type_level *
-push_type_level (stack, obstack)
- struct stack_level *stack;
- struct obstack *obstack;
-{
- struct type_level tem;
-
- tem.base.prev = stack;
-
- obstack_finish (&type_obstack_entries);
- tem.entries = (char *) obstack_base (&type_obstack_entries);
- tem.len = 0;
- tem.type = NULL_TREE;
-
- return (struct type_level *)push_stack_level (obstack, (char *)&tem, sizeof (tem));
-}
-
-/* Discard a level of type memoization context. */
-
-static struct type_level *
-pop_type_level (stack)
- struct type_level *stack;
-{
- obstack_free (&type_obstack_entries, stack->entries);
- return (struct type_level *)pop_stack_level ((struct stack_level *)stack);
-}
-
-/* Make something that looks like a TREE_LIST, but
- do it on the type_obstack_entries obstack. */
-static tree
-my_tree_cons (purpose, value, chain)
- tree purpose, value, chain;
-{
- tree p = (tree)obstack_alloc (&type_obstack_entries, sizeof (struct tree_list));
- ++my_tree_node_counter;
- TREE_TYPE (p) = NULL_TREE;
- ((HOST_WIDE_INT *)p)[3] = 0;
- TREE_SET_CODE (p, TREE_LIST);
- TREE_PURPOSE (p) = purpose;
- TREE_VALUE (p) = value;
- TREE_CHAIN (p) = chain;
- return p;
-}
-
-static tree
-my_build_string (str)
- char *str;
-{
- tree p = (tree)obstack_alloc (&type_obstack_entries, sizeof (struct tree_string));
- ++my_tree_node_counter;
- TREE_TYPE (p) = 0;
- ((int *)p)[3] = 0;
- TREE_SET_CODE (p, STRING_CST);
- TREE_STRING_POINTER (p) = str;
- TREE_STRING_LENGTH (p) = strlen (str);
- return p;
-}
-\f
-/* Memoizing machinery to make searches for multiple inheritance
- reasonably efficient. */
-#define MEMOIZE_HASHSIZE 8
-typedef struct memoized_entry
-{
- struct memoized_entry *chain;
- int uid;
- tree data_members[MEMOIZE_HASHSIZE];
- tree function_members[MEMOIZE_HASHSIZE];
-} *ME;
-
-#define MEMOIZED_CHAIN(ENTRY) (((ME)ENTRY)->chain)
-#define MEMOIZED_UID(ENTRY) (((ME)ENTRY)->uid)
-#define MEMOIZED_FIELDS(ENTRY,INDEX) (((ME)ENTRY)->data_members[INDEX])
-#define MEMOIZED_FNFIELDS(ENTRY,INDEX) (((ME)ENTRY)->function_members[INDEX])
-/* The following is probably a lousy hash function. */
-#define MEMOIZED_HASH_FN(NODE) (((long)(NODE)>>4)&(MEMOIZE_HASHSIZE - 1))
-
-static struct memoized_entry *
-my_new_memoized_entry (chain)
- struct memoized_entry *chain;
-{
- struct memoized_entry *p =
- (struct memoized_entry *)obstack_alloc (&type_obstack_entries,
- sizeof (struct memoized_entry));
- bzero ((char *) p, sizeof (struct memoized_entry));
- MEMOIZED_CHAIN (p) = chain;
- MEMOIZED_UID (p) = ++my_memoized_entry_counter;
- return p;
-}
-
-/* Make an entry in the memoized table for type TYPE
- that the entry for NAME is FIELD. */
-
-tree
-make_memoized_table_entry (type, name, function_p)
- tree type, name;
- int function_p;
-{
- int index = MEMOIZED_HASH_FN (name);
- tree entry, *prev_entry;
-
- memoized_adds[function_p] += 1;
- if (CLASSTYPE_MTABLE_ENTRY (type) == 0)
- {
- obstack_ptr_grow (&type_obstack, type);
- obstack_blank (&type_obstack, sizeof (struct memoized_entry *));
- CLASSTYPE_MTABLE_ENTRY (type) = (char *)my_new_memoized_entry ((struct memoized_entry *)0);
- type_stack->len++;
- if (type_stack->len * 2 >= type_stack->base.limit)
- my_friendly_abort (88);
- }
- if (function_p)
- prev_entry = &MEMOIZED_FNFIELDS (CLASSTYPE_MTABLE_ENTRY (type), index);
- else
- prev_entry = &MEMOIZED_FIELDS (CLASSTYPE_MTABLE_ENTRY (type), index);
-
- entry = my_tree_cons (name, NULL_TREE, *prev_entry);
- *prev_entry = entry;
-
- /* Don't know the error message to give yet. */
- TREE_TYPE (entry) = error_mark_node;
-
- return entry;
-}
-
-/* When a new function or class context is entered, we build
- a table of types which have been searched for members.
- The table is an array (obstack) of types. When a type is
- entered into the obstack, its CLASSTYPE_MTABLE_ENTRY
- field is set to point to a new record, of type struct memoized_entry.
-
- A non-NULL TREE_TYPE of the entry contains an access control error message.
-
- The slots for the data members are arrays of tree nodes.
- These tree nodes are lists, with the TREE_PURPOSE
- of this list the known member name, and the TREE_VALUE
- as the FIELD_DECL for the member.
-
- For member functions, the TREE_PURPOSE is again the
- name of the member functions for that class,
- and the TREE_VALUE of the list is a pairs
- whose TREE_PURPOSE is a member functions of this name,
- and whose TREE_VALUE is a list of known argument lists this
- member function has been called with. The TREE_TYPE of the pair,
- if non-NULL, is an error message to print. */
-
-/* Tell search machinery that we are entering a new context, and
- to update tables appropriately.
-
- TYPE is the type of the context we are entering, which can
- be NULL_TREE if we are not in a class's scope.
-
- USE_OLD, if nonzero tries to use previous context. */
-void
-push_memoized_context (type, use_old)
- tree type;
- int use_old;
-{
- int len;
- tree *tem;
-
- if (prev_type_stack)
- {
- if (use_old && prev_type_memoized == type)
- {
-#ifdef GATHER_STATISTICS
- n_contexts_saved++;
-#endif
- type_stack = prev_type_stack;
- prev_type_stack = 0;
-
- tem = &type_stack->base.first[0];
- len = type_stack->len;
- while (len--)
- CLASSTYPE_MTABLE_ENTRY (tem[len*2]) = (char *)tem[len*2+1];
- return;
- }
- /* Otherwise, need to pop old stack here. */
- type_stack = pop_type_level (prev_type_stack);
- prev_type_memoized = 0;
- prev_type_stack = 0;
- }
-
- type_stack = push_type_level ((struct stack_level *)type_stack,
- &type_obstack);
- type_stack->type = type;
-}
-
-/* Tell search machinery that we have left a context.
- We do not currently save these contexts for later use.
- If we wanted to, we could not use pop_search_level, since
- poping that level allows the data we have collected to
- be clobbered; a stack of obstacks would be needed. */
-void
-pop_memoized_context (use_old)
- int use_old;
-{
- int len;
- tree *tem = &type_stack->base.first[0];
-
- if (! flag_save_memoized_contexts)
- use_old = 0;
- else if (use_old)
- {
- len = type_stack->len;
- while (len--)
- tem[len*2+1] = (tree)CLASSTYPE_MTABLE_ENTRY (tem[len*2]);
-
- prev_type_stack = type_stack;
- prev_type_memoized = type_stack->type;
- }
-
- if (flag_memoize_lookups)
- {
- len = type_stack->len;
- while (len--)
- CLASSTYPE_MTABLE_ENTRY (tem[len*2])
- = (char *)MEMOIZED_CHAIN (CLASSTYPE_MTABLE_ENTRY (tem[len*2]));
- }
- if (! use_old)
- type_stack = pop_type_level (type_stack);
- else
- type_stack = (struct type_level *)type_stack->base.prev;
-}
\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
the first one that is found by going through the least number of
- virtual bases. DEPTH should be NULL_PTR. */
+ virtual bases.
+
+ This uses a clever algorithm that updates *depth when we find the vbase,
+ and cuts off other paths of search when they reach that depth. */
+
static tree
-get_vbase (parent, binfo, depth)
+get_vbase_1 (parent, binfo, depth)
tree parent, binfo;
unsigned int *depth;
{
int i, n_baselinks;
tree rval = NULL_TREE;
- if (depth == 0)
- {
- unsigned int d = (unsigned int)-1;
- return get_vbase (parent, binfo, &d);
- }
-
if (BINFO_TYPE (binfo) == parent && TREE_VIA_VIRTUAL (binfo))
{
*depth = 0;
if (*depth == 0)
break;
- nrval = get_vbase (parent, base_binfo, depth);
+ nrval = get_vbase_1 (parent, base_binfo, depth);
if (nrval)
rval = nrval;
}
return rval;
}
+/* Return the shortest path to vbase PARENT within BINFO, ignoring
+ access and ambiguity. */
+
+tree
+get_vbase (parent, binfo)
+ tree parent;
+ tree binfo;
+{
+ unsigned int d = (unsigned int)-1;
+ return get_vbase_1 (parent, binfo, &d);
+}
+
/* Convert EXPR to a virtual base class of type TYPE. We know that
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. */
-tree
+
+static tree
convert_pointer_to_vbase (type, expr)
tree type;
tree expr;
{
- tree vb = get_vbase (type, TYPE_BINFO (TREE_TYPE (TREE_TYPE (expr))), NULL_PTR);
+ tree vb = get_vbase (type, TYPE_BINFO (TREE_TYPE (TREE_TYPE (expr))));
return convert_pointer_to_real (vb, expr);
}
-/* This is the newer recursive depth first search routine. */
-#if 0 /* unused */
-/* Return non-zero if PARENT is directly derived from TYPE. By directly
- we mean it's only one step up the inheritance lattice. We check this
- by walking horizontally across the types that TYPE directly inherits
- from, to see if PARENT is among them. This is used by get_binfo and
- by compute_access. */
-static int
-immediately_derived (parent, type)
- tree parent, type;
-{
- if (TYPE_BINFO (type))
- {
- tree binfos = BINFO_BASETYPES (TYPE_BINFO (type));
- int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
-
- for (i = 0; i < n_baselinks; i++)
- {
- tree base_binfo = TREE_VEC_ELT (binfos, i);
-
- if (parent == BINFO_TYPE (base_binfo))
- return 1;
- }
- }
- return 0;
-}
-#endif
-
/* Check whether the type given in BINFO is derived from PARENT. If
it isn't, return 0. If it is, but the derivation is MI-ambiguous
AND protect != 0, emit an error message and return error_mark_node.
register tree parent, binfo;
int protect;
{
- tree type;
+ tree type = NULL_TREE;
int dist;
tree rval = NULL_TREE;
}
/* This is the newer depth first get_base_distance routine. */
+
static int
-get_base_distance_recursive (binfo, depth, is_private, basetype_path, rval,
- rval_private_ptr, new_binfo_ptr, parent, path_ptr,
- protect, via_virtual_ptr, via_virtual)
- tree binfo, basetype_path, *new_binfo_ptr, parent, *path_ptr;
- int *rval_private_ptr, depth, is_private, rval, protect, *via_virtual_ptr,
- via_virtual;
+get_base_distance_recursive (binfo, depth, is_private, rval,
+ rval_private_ptr, new_binfo_ptr, parent,
+ protect, via_virtual_ptr, via_virtual,
+ current_scope_in_chain)
+ tree binfo;
+ int depth, is_private, rval;
+ int *rval_private_ptr;
+ tree *new_binfo_ptr, parent;
+ int protect, *via_virtual_ptr, via_virtual;
+ int current_scope_in_chain;
{
tree binfos;
int i, n_baselinks;
+ if (protect
+ && !current_scope_in_chain
+ && is_friend (BINFO_TYPE (binfo), current_scope ()))
+ current_scope_in_chain = 1;
+
if (BINFO_TYPE (binfo) == parent || binfo == parent)
{
+ int better = 0;
+
if (rval == -1)
+ /* This is the first time we've found parent. */
+ better = 1;
+ else if (tree_int_cst_equal (BINFO_OFFSET (*new_binfo_ptr),
+ BINFO_OFFSET (binfo))
+ && *via_virtual_ptr && via_virtual)
+ {
+ /* A new path to the same vbase. If this one has better
+ access or is shorter, take it. */
+
+ if (protect)
+ better = *rval_private_ptr - is_private;
+ if (better == 0)
+ better = rval - depth;
+ }
+ else
+ {
+ /* Ambiguous base class. */
+ rval = depth = -2;
+
+ /* If we get an ambiguity between virtual and non-virtual base
+ class, return the non-virtual in case we are ignoring
+ ambiguity. */
+ better = *via_virtual_ptr - via_virtual;
+ }
+
+ if (better > 0)
{
rval = depth;
*rval_private_ptr = is_private;
*new_binfo_ptr = binfo;
*via_virtual_ptr = via_virtual;
}
- else
- {
- int same_object = (tree_int_cst_equal (BINFO_OFFSET (*new_binfo_ptr),
- BINFO_OFFSET (binfo))
- && *via_virtual_ptr && via_virtual);
-
- if (*via_virtual_ptr && via_virtual==0)
- {
- *rval_private_ptr = is_private;
- *new_binfo_ptr = binfo;
- *via_virtual_ptr = via_virtual;
- }
- else if (same_object)
- {
- if (*rval_private_ptr && ! is_private)
- {
- *rval_private_ptr = is_private;
- *new_binfo_ptr = binfo;
- *via_virtual_ptr = via_virtual;
- }
- return rval;
- }
- rval = -2;
- }
return rval;
}
{
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 || TREE_CODE (parent) == TREE_VEC)
- {
- int via_private
- = (protect
- && (is_private
- || (!TREE_VIA_PUBLIC (base_binfo)
- && !is_friend (BINFO_TYPE (binfo), current_scope ()))));
- int this_virtual = via_virtual || TREE_VIA_VIRTUAL (base_binfo);
- int was;
-
- /* When searching for a non-virtual, we cannot mark
- virtually found binfos. */
- if (! this_virtual)
- SET_BINFO_MARKED (base_binfo);
-
-#define WATCH_VALUES(rval, via_private) (rval == -1 ? 3 : via_private)
-
- was = WATCH_VALUES (rval, *via_virtual_ptr);
- rval = get_base_distance_recursive (base_binfo, depth, via_private,
- binfo, rval, rval_private_ptr,
- new_binfo_ptr, parent, path_ptr,
- protect, via_virtual_ptr,
- this_virtual);
- /* watch for updates; only update if path is good. */
- if (path_ptr && WATCH_VALUES (rval, *via_virtual_ptr) != was)
- BINFO_INHERITANCE_CHAIN (base_binfo) = binfo;
- if (rval == -2 && *via_virtual_ptr == 0)
- return rval;
+ int via_private
+ = (protect
+ && (is_private
+ || (!TREE_VIA_PUBLIC (base_binfo)
+ && !(TREE_VIA_PROTECTED (base_binfo)
+ && current_scope_in_chain)
+ && !is_friend (BINFO_TYPE (binfo), current_scope ()))));
+ int this_virtual = via_virtual || TREE_VIA_VIRTUAL (base_binfo);
-#undef WATCH_VALUES
+ rval = get_base_distance_recursive (base_binfo, depth, via_private,
+ rval, rval_private_ptr,
+ new_binfo_ptr, parent,
+ protect, via_virtual_ptr,
+ this_virtual,
+ current_scope_in_chain);
- }
+ /* If we've found a non-virtual, ambiguous base class, we don't need
+ to keep searching. */
+ if (rval == -2 && *via_virtual_ptr == 0)
+ return rval;
}
return rval;
/* Return the number of levels between type PARENT and the type given
in BINFO, following the leftmost path to PARENT not found along a
virtual path, if there are no real PARENTs (all come from virtual
- base classes), then follow the leftmost path to PARENT.
+ base classes), then follow the shortest public path to PARENT.
Return -1 if TYPE is not derived from PARENT.
Return -2 if PARENT is an ambiguous base class of TYPE, and PROTECT is
{
int rval;
int rval_private = 0;
- tree type;
+ tree type = NULL_TREE;
tree new_binfo = NULL_TREE;
int via_virtual;
int watch_access = protect;
+ /* Should we be completing types here? */
if (TREE_CODE (parent) != TREE_VEC)
- parent = TYPE_MAIN_VARIANT (parent);
+ parent = complete_type (TYPE_MAIN_VARIANT (parent));
+ else
+ complete_type (TREE_TYPE (parent));
if (TREE_CODE (binfo) == TREE_VEC)
type = BINFO_TYPE (binfo);
else if (IS_AGGR_TYPE_CODE (TREE_CODE (binfo)))
{
- type = binfo;
+ type = complete_type (binfo);
binfo = TYPE_BINFO (type);
if (path_ptr)
- BINFO_INHERITANCE_CHAIN (binfo) = NULL_TREE;
+ my_friendly_assert (BINFO_INHERITANCE_CHAIN (binfo) == NULL_TREE,
+ 980827);
}
else
my_friendly_abort (92);
if (path_ptr)
watch_access = 1;
- rval = get_base_distance_recursive (binfo, 0, 0, NULL_TREE, -1,
+ rval = get_base_distance_recursive (binfo, 0, 0, -1,
&rval_private, &new_binfo, parent,
- path_ptr, watch_access, &via_virtual, 0);
-
- dfs_walk (binfo, dfs_unmark, markedp);
+ watch_access, &via_virtual, 0,
+ 0);
/* Access restrictions don't count if we found an ambiguous basetype. */
if (rval == -2 && protect >= 0)
if (rval && protect && rval_private)
return -3;
- /* find real virtual base classes. */
+ /* If they gave us the real vbase binfo, which isn't in the main binfo
+ 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)))
{
- BINFO_INHERITANCE_CHAIN (parent) = binfo;
+ my_friendly_assert (BINFO_INHERITANCE_CHAIN (parent) == binfo, 980827);
new_binfo = parent;
rval = 1;
}
/* Do a 1-level search for NAME as a member of TYPE. The caller must
figure out whether it can access this field. (Since it is only one
level, this is reasonable.) */
+
static tree
lookup_field_1 (type, name)
tree type, name;
{
- register tree field = TYPE_FIELDS (type);
+ register tree field;
+
+ if (TREE_CODE (type) == TEMPLATE_TYPE_PARM
+ || TREE_CODE (type) == TEMPLATE_TEMPLATE_PARM)
+ /* The TYPE_FIELDS of a TEMPLATE_TYPE_PARM are not fields at all;
+ instead TYPE_FIELDS is the TEMPLATE_PARM_INDEX. (Miraculously,
+ the code often worked even when we treated the index as a list
+ of fields!) */
+ return NULL_TREE;
+
+ field = TYPE_FIELDS (type);
#ifdef GATHER_STATISTICS
n_calls_lookup_field_1++;
-#endif
+#endif /* GATHER_STATISTICS */
while (field)
{
#ifdef GATHER_STATISTICS
n_fields_searched++;
-#endif
+#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)
{
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)
/* There are a number of cases we need to be aware of here:
current_class_type current_function_decl
- * global NULL NULL
- * fn-local NULL SET
- * class-local SET NULL
- * class->fn SET SET
- * fn->class SET SET
+ global NULL NULL
+ fn-local NULL SET
+ class-local SET NULL
+ class->fn SET SET
+ fn->class SET SET
Those last two make life interesting. If we're in a function which is
itself inside a class, we need decls to go into the fn's decls (our
second case below). But if we're in a class and the class itself is
inside a function, we need decls to go into the decls for the class. To
- achieve this last goal, we must see if, when both current_class_decl and
+ achieve this last goal, we must see if, when both current_class_ptr and
current_function_decl are set, the class was declared inside that
function. If so, we know to put the decls into the class's scope. */
lexical scope because it is protected.
access_private_node means that the field cannot be accessed by the current
- lexical scope because it is private. */
+ lexical scope because it is private. */
#if 0
#define PUBLIC_RETURN return (DECL_PUBLIC (field) = 1), access_public_node
/* 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)));
+ 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 access_public_node;
previous_scope = current_scope ();
-
- context = DECL_CLASS_CONTEXT (field);
- if (context == NULL_TREE)
- context = DECL_CONTEXT (field);
+
+ context = DECL_REAL_CONTEXT (field);
/* 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. In this case, DECL_FIELD_CONTEXT is correct. */
- if (context && TREE_CODE (context) == UNION_TYPE
- && ANON_AGGRNAME_P (TYPE_IDENTIFIER (context)))
- context = DECL_FIELD_CONTEXT (field);
+ the anonymous union. */
+ if (context && ANON_UNION_TYPE_P (context)
+ && TREE_CODE (field) == FIELD_DECL)
+ context = TYPE_CONTEXT (context);
/* Virtual function tables are never private. But we should know that
we are looking for this, and not even try to hide it. */
else if (TREE_PROTECTED (field))
{
if (current_class_type
- && static_mem
- && ACCESSIBLY_DERIVED_FROM_P (context, current_class_type))
+ && (static_mem || DECL_CONSTRUCTOR_P (field))
+ && ACCESSIBLY_DERIVED_FROM_P (context, current_class_type))
PUBLIC_RETURN;
else
PROTECTED_RETURN;
else
break;
}
- reverse_path (basetype_path);
/* No special visibilities apply. Use normal rules. */
found as a base class and sub-object of the object denoted by
BINFO. This routine relies upon binfos not being shared, except
for binfos for virtual bases. */
+
static int
is_subobject_of_p (parent, binfo)
tree parent, binfo;
correspond to ANSI working paper Sept 17, 1992 10p4. The two
binfos given are the binfos corresponding to the particular places
the FIELD_DECLs are found. This routine relies upon binfos not
- being shared, except for virtual bases. */
+ being shared, except for virtual bases. */
+
static int
hides (hider_binfo, hidee_binfo)
tree hider_binfo, hidee_binfo;
part is always true is the second part is true.
When hider and hidee are the same (two ways to get to the exact
- same member) we consider either one as hiding the other. */
+ same member) we consider either one as hiding the other. */
return is_subobject_of_p (hidee_binfo, hider_binfo);
}
/* Very similar to lookup_fnfields_1 but it ensures that at least one
function was declared inside the class given by TYPE. It really should
only return functions that match the given TYPE. */
+
static int
lookup_fnfields_here (type, name)
tree type, name;
{
- int index = lookup_fnfields_1 (type, name);
+ int idx = lookup_fnfields_1 (type, name);
tree fndecls;
- if (index <= 0)
- return index;
- fndecls = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), index);
+ /* ctors and dtors are always only in the right class. */
+ if (idx <= 1)
+ return idx;
+ fndecls = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), idx);
while (fndecls)
{
- if (TYPE_MAIN_VARIANT (DECL_CLASS_CONTEXT (fndecls))
+ if (TYPE_MAIN_VARIANT (DECL_CLASS_CONTEXT (OVL_CURRENT (fndecls)))
== TYPE_MAIN_VARIANT (type))
- return index;
- fndecls = TREE_CHAIN (fndecls);
+ return idx;
+ fndecls = OVL_CHAIN (fndecls);
}
return -1;
}
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;
{
int head = 0, tail = 0;
- tree rval, rval_binfo = NULL_TREE, rval_binfo_h;
- tree type, basetype_chain, basetype_path;
+ 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;
/* 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 the binfo hierarchy owned by TYPE_BINFO of
+ is we always go into the binfo hierarchy owned by TYPE_BINFO of
virtual base classes, as we cross virtual base class lines. This way
we know that binfo of a virtual base class will always == itself when
found along any line. (mrs) */
char *errstr = 0;
- /* Set this to nonzero if we don't know how to compute
- accurate error messages for access control. */
- int index = MEMOIZED_HASH_FN (name);
-
+#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 (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))
+ return field;
+ }
if (TREE_CODE (xbasetype) == TREE_VEC)
{
else if (IS_AGGR_TYPE_CODE (TREE_CODE (xbasetype)))
{
type = xbasetype;
- basetype_path = TYPE_BINFO (xbasetype);
- BINFO_VIA_PUBLIC (basetype_path) = 1;
- BINFO_INHERITANCE_CHAIN (basetype_path) = NULL_TREE;
+ basetype_path = TYPE_BINFO (type);
+ my_friendly_assert (BINFO_INHERITANCE_CHAIN (basetype_path) == NULL_TREE,
+ 980827);
}
- else my_friendly_abort (97);
-
- if (CLASSTYPE_MTABLE_ENTRY (type))
- {
- tree tem = MEMOIZED_FIELDS (CLASSTYPE_MTABLE_ENTRY (type), index);
+ else
+ my_friendly_abort (97);
- while (tem && TREE_PURPOSE (tem) != name)
- {
- memoized_fields_searched[0]++;
- tem = TREE_CHAIN (tem);
- }
- if (tem)
- {
- if (protect && TREE_TYPE (tem))
- {
- error (TREE_STRING_POINTER (TREE_TYPE (tem)),
- IDENTIFIER_POINTER (name),
- TYPE_NAME_STRING (DECL_FIELD_CONTEXT (TREE_VALUE (tem))));
- return error_mark_node;
- }
- if (TREE_VALUE (tem) == NULL_TREE)
- memoized_fast_rejects[0] += 1;
- else
- memoized_fast_finds[0] += 1;
- return TREE_VALUE (tem);
- }
- }
+ complete_type (type);
#ifdef GATHER_STATISTICS
n_calls_lookup_field++;
-#endif
- if (protect && flag_memoize_lookups && ! global_bindings_p ())
- entry = make_memoized_table_entry (type, name, 0);
- else
- entry = 0;
+#endif /* GATHER_STATISTICS */
rval = lookup_field_1 (type, name);
}
}
- if (entry)
- {
- if (errstr)
- {
- /* This depends on behavior of lookup_field_1! */
- tree error_string = my_build_string (errstr);
- TREE_TYPE (entry) = error_string;
- }
- else
- {
- /* Let entry know there is no problem with this access. */
- TREE_TYPE (entry) = NULL_TREE;
- }
- TREE_VALUE (entry) = rval;
- }
-
- if (errstr && protect)
- {
- cp_error (errstr, name, type);
- return error_mark_node;
- }
- return rval;
+ rval_binfo = basetype_path;
+ goto out;
}
- basetype_chain = build_tree_list (NULL_TREE, basetype_path);
- TREE_VIA_PUBLIC (basetype_chain) = TREE_VIA_PUBLIC (basetype_path);
- TREE_VIA_PROTECTED (basetype_chain) = TREE_VIA_PROTECTED (basetype_path);
- TREE_VIA_VIRTUAL (basetype_chain) = TREE_VIA_VIRTUAL (basetype_path);
+ basetype_chain = build_expr_list (NULL_TREE, basetype_path);
- /* The ambiguity check relies upon breadth first searching. */
+ /* The ambiguity check relies upon breadth first searching. */
search_stack = push_search_level (search_stack, &search_obstack);
binfo = basetype_path;
tree btypes;
SET_BINFO_FIELDS_MARKED (base_binfo);
- btypes = my_tree_cons (NULL_TREE, base_binfo, basetype_chain);
- TREE_VIA_PUBLIC (btypes) = TREE_VIA_PUBLIC (base_binfo);
- TREE_VIA_PROTECTED (btypes) = TREE_VIA_PROTECTED (base_binfo);
- TREE_VIA_VIRTUAL (btypes) = TREE_VIA_VIRTUAL (base_binfo);
+ btypes = scratch_tree_cons (NULL_TREE, base_binfo, basetype_chain);
if (TREE_VIA_VIRTUAL (base_binfo))
- btypes = tree_cons (NULL_TREE,
+ btypes = scratch_tree_cons (NULL_TREE,
TYPE_BINFO (BINFO_TYPE (TREE_VEC_ELT (BINFO_BASETYPES (binfo_h), i))),
btypes);
else
- btypes = tree_cons (NULL_TREE,
+ btypes = scratch_tree_cons (NULL_TREE,
TREE_VEC_ELT (BINFO_BASETYPES (binfo_h), i),
btypes);
obstack_ptr_grow (&search_obstack, btypes);
basetype_chain = TREE_CHAIN (basetype_chain);
basetype_path = TREE_VALUE (basetype_chain);
if (TREE_CHAIN (basetype_chain))
- BINFO_INHERITANCE_CHAIN (basetype_path) = TREE_VALUE (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
- BINFO_INHERITANCE_CHAIN (basetype_path) = NULL_TREE;
+ my_friendly_assert (BINFO_INHERITANCE_CHAIN (basetype_path)
+ == NULL_TREE, 980827);
binfo = basetype_path;
type = BINFO_TYPE (binfo);
else if (rval_binfo && hides (rval_binfo_h, binfo_h))
{
/* This is ok, the member found is in rval_binfo, not
- here (binfo). */
+ 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. */
+ rval_binfo. */
if (nval)
{
rval = nval;
- if (entry || protect)
+ if (protect)
this_v = compute_access (basetype_path, rval);
/* These may look ambiguous, but they really are not. */
if (vbase_name_p)
}
else
{
- /* Undo finding it before, as something else hides it. */
+ /* Undo finding it before, as something else hides it. */
rval = NULL_TREE;
}
rval_binfo = binfo;
}
else
{
- /* This is ambiguous. */
+ /* This is ambiguous. */
errstr = "request for member `%D' is ambiguous";
- protect = 2;
+ protect += 2;
break;
}
}
tree *tp = search_stack->first;
tree *search_tail = tp + tail;
- if (entry)
- TREE_VALUE (entry) = rval;
-
if (rval_binfo)
{
type = BINFO_TYPE (rval_binfo);
/* If this FIELD_DECL defines its own access level, deal with that. */
if (rval && errstr == 0
- && ((protect&1) || entry)
+ && (protect & 1)
&& DECL_LANG_SPECIFIC (rval)
&& DECL_ACCESS (rval))
{
/* 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;
+ tree new_v = NULL_TREE;
if (this_v != access_default_node)
new_v = compute_access (TREE_VALUE (TREE_CHAIN (*tp)), rval);
: "member `%D' is from protected base class";
}
- if (entry)
+ out:
+ if (protect == 2)
{
- if (errstr)
- {
- tree error_string = my_build_string (errstr);
- /* Save error message with entry. */
- TREE_TYPE (entry) = error_string;
- }
- else
- {
- /* Mark entry as having no error string. */
- TREE_TYPE (entry) = NULL_TREE;
- }
+ /* If we are not interested in ambiguities, don't report them,
+ just return NULL_TREE. */
+ rval = NULL_TREE;
+ protect = 0;
}
if (errstr && protect)
cp_error (errstr, name, type);
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() {}
+
+ 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))
+ {
+ /* We need to return a member template class so we can define partial
+ specializations. Is there a better way? */
+ if (DECL_CLASS_TEMPLATE_P (rval))
+ return 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);
+ }
+
return rval;
}
/* Try to find NAME inside a nested class. */
+
tree
lookup_nested_field (name, complain)
tree name;
register tree t;
tree id = NULL_TREE;
- if (TREE_CHAIN (current_class_type))
+ 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 = TREE_CHAIN (current_class_type);
+ for (t = TYPE_MAIN_DECL (current_class_type);
t && DECL_CONTEXT (t);
- t = TREE_CHAIN (DECL_CONTEXT (t)))
+ t = TYPE_MAIN_DECL (DECL_CONTEXT (t)))
{
if (TREE_CODE (DECL_CONTEXT (t)) != RECORD_TYPE)
break;
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. */
- error ("assignment to non-static member `%s' of enclosing class `%s'",
- lang_printable_name (id),
- IDENTIFIER_POINTER (TYPE_IDENTIFIER
- (DECL_CONTEXT (t))));
+ 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;
/* 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
lookup_fnfields_1 (type, name)
tree type, name;
{
- register tree method_vec = CLASSTYPE_METHOD_VEC (type);
+ register tree method_vec
+ = CLASS_TYPE_P (type) ? CLASSTYPE_METHOD_VEC (type) : NULL_TREE;
if (method_vec != 0)
{
#ifdef GATHER_STATISTICS
n_calls_lookup_fnfields_1++;
-#endif
- if (*methods && name == constructor_name (type))
+#endif /* GATHER_STATISTICS */
+
+ /* Constructors are first... */
+ if (*methods && name == ctor_identifier)
return 0;
- while (++methods != end)
+ /* and destructors are second. */
+ if (*++methods && name == dtor_identifier)
+ return 1;
+
+ while (++methods != end && *methods)
{
#ifdef GATHER_STATISTICS
n_outer_fields_searched++;
-#endif
- if (DECL_NAME (*methods) == name)
+#endif /* GATHER_STATISTICS */
+ if (DECL_NAME (OVL_CURRENT (*methods)) == name)
break;
}
- if (methods != end)
+
+ /* 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))
+ {
+ methods = &TREE_VEC_ELT (method_vec, 0) + 1;
+
+ while (++methods != end && *methods)
+ {
+ tree method_name = DECL_NAME (OVL_CURRENT (*methods));
+
+ if (!IDENTIFIER_TYPENAME_P (method_name))
+ {
+ /* 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;
+ }
+ }
+
+ if (methods != end && *methods)
return methods - &TREE_VEC_ELT (method_vec, 0);
}
which gives the following information (in a list):
TREE_TYPE: list of basetypes needed to get to...
- TREE_VALUE: list of all functions in of given type
+ TREE_VALUE: list of all functions in a given type
which have name NAME.
No access information is computed by this function,
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;
{
int head = 0, tail = 0;
- tree type, rval, rval_binfo = NULL_TREE, rvals = NULL_TREE, rval_binfo_h;
- tree entry, binfo, basetype_chain, binfo_h;
- int find_all = 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
/* 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 the binfo hierarchy owned by TYPE_BINFO of
+ is we always go into the binfo hierarchy owned by TYPE_BINFO of
virtual base classes, as we cross virtual base class lines. This way
we know that binfo of a virtual base class will always == itself when
found along any line. (mrs) */
char *errstr = 0;
- /* Set this to nonzero if we don't know how to compute
- accurate error messages for access control. */
- int index = MEMOIZED_HASH_FN (name);
-
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 = BINFO_TYPE (basetype_path);
-
- /* The memoization code is in need of maintenance. */
- if (!find_all && CLASSTYPE_MTABLE_ENTRY (type))
- {
- tree tem = MEMOIZED_FNFIELDS (CLASSTYPE_MTABLE_ENTRY (type), index);
-
- while (tem && TREE_PURPOSE (tem) != name)
- {
- memoized_fields_searched[1]++;
- tem = TREE_CHAIN (tem);
- }
- if (tem)
- {
- if (protect && TREE_TYPE (tem))
- {
- error (TREE_STRING_POINTER (TREE_TYPE (tem)),
- IDENTIFIER_POINTER (name),
- TYPE_NAME_STRING (DECL_CLASS_CONTEXT (TREE_VALUE (TREE_VALUE (tem)))));
- return error_mark_node;
- }
- if (TREE_VALUE (tem) == NULL_TREE)
- {
- memoized_fast_rejects[1] += 1;
- return NULL_TREE;
- }
- else
- {
- /* Want to return this, but we must make sure
- that access information is consistent. */
- tree baselink = TREE_VALUE (tem);
- tree memoized_basetypes = TREE_PURPOSE (baselink);
- tree these_basetypes = basetype_path;
- while (memoized_basetypes && these_basetypes)
- {
- memoized_fields_searched[1]++;
- if (TREE_VALUE (memoized_basetypes) != these_basetypes)
- break;
- memoized_basetypes = TREE_CHAIN (memoized_basetypes);
- these_basetypes = BINFO_INHERITANCE_CHAIN (these_basetypes);
- }
- /* The following statement is true only when both are NULL. */
- if (memoized_basetypes == these_basetypes)
- {
- memoized_fast_finds[1] += 1;
- return TREE_VALUE (tem);
- }
- /* else, we must re-find this field by hand. */
- baselink = tree_cons (basetype_path, TREE_VALUE (baselink), TREE_CHAIN (baselink));
- return baselink;
- }
- }
- }
+ type = complete_type (BINFO_TYPE (basetype_path));
#ifdef GATHER_STATISTICS
n_calls_lookup_fnfields++;
-#endif
- if (protect && flag_memoize_lookups && ! global_bindings_p ())
- entry = make_memoized_table_entry (type, name, 1);
- else
- entry = 0;
+#endif /* GATHER_STATISTICS */
- index = lookup_fnfields_here (type, name);
- if (index >= 0 || lookup_field_1 (type, name))
+ idx = lookup_fnfields_here (type, name);
+ if (idx >= 0 || lookup_field_1 (type, name))
{
rval_binfo = basetype_path;
rval_binfo_h = rval_binfo;
}
- if (index >= 0)
+ if (idx >= 0)
{
- rval = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), index);
- rvals = my_tree_cons (basetype_path, rval, rvals);
+ 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), index);
-
- if (entry)
- {
- TREE_VALUE (entry) = rvals;
- TREE_TYPE (entry) = NULL_TREE;
- }
+ TREE_TYPE (rvals) = TREE_VEC_ELT (CLASSTYPE_BASELINK_VEC (type), idx);
return rvals;
}
rval = NULL_TREE;
+ 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;
+ }
+
if (basetype_path == TYPE_BINFO (type))
{
basetype_chain = CLASSTYPE_BINFO_AS_LIST (type);
- TREE_VIA_PUBLIC (basetype_chain) = 1;
- BINFO_VIA_PUBLIC (basetype_path) = 1;
- BINFO_INHERITANCE_CHAIN (basetype_path) = NULL_TREE;
+ my_friendly_assert (BINFO_INHERITANCE_CHAIN (basetype_path) == NULL_TREE,
+ 980827);
}
else
- {
- basetype_chain = build_tree_list (NULL_TREE, basetype_path);
- TREE_VIA_PUBLIC (basetype_chain) = TREE_VIA_PUBLIC (basetype_path);
- TREE_VIA_PROTECTED (basetype_chain) = TREE_VIA_PROTECTED (basetype_path);
- TREE_VIA_VIRTUAL (basetype_chain) = TREE_VIA_VIRTUAL (basetype_path);
- }
+ basetype_chain = build_expr_list (NULL_TREE, basetype_path);
- /* The ambiguity check relies upon breadth first searching. */
+ /* The ambiguity check relies upon breadth first searching. */
search_stack = push_search_level (search_stack, &search_obstack);
binfo = basetype_path;
{
tree binfos = BINFO_BASETYPES (binfo);
int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
- int index;
+ int idx;
/* Process and/or queue base types. */
for (i = 0; i < n_baselinks; i++)
tree btypes;
SET_BINFO_FIELDS_MARKED (base_binfo);
- btypes = my_tree_cons (NULL_TREE, base_binfo, basetype_chain);
- TREE_VIA_PUBLIC (btypes) = TREE_VIA_PUBLIC (base_binfo);
- TREE_VIA_PROTECTED (btypes) = TREE_VIA_PROTECTED (base_binfo);
- TREE_VIA_VIRTUAL (btypes) = TREE_VIA_VIRTUAL (base_binfo);
+ btypes = scratch_tree_cons (NULL_TREE, base_binfo, basetype_chain);
if (TREE_VIA_VIRTUAL (base_binfo))
- btypes = tree_cons (NULL_TREE,
+ btypes = scratch_tree_cons (NULL_TREE,
TYPE_BINFO (BINFO_TYPE (TREE_VEC_ELT (BINFO_BASETYPES (binfo_h), i))),
btypes);
else
- btypes = tree_cons (NULL_TREE,
+ btypes = scratch_tree_cons (NULL_TREE,
TREE_VEC_ELT (BINFO_BASETYPES (binfo_h), i),
btypes);
obstack_ptr_grow (&search_obstack, btypes);
basetype_chain = TREE_CHAIN (basetype_chain);
basetype_path = TREE_VALUE (basetype_chain);
if (TREE_CHAIN (basetype_chain))
- BINFO_INHERITANCE_CHAIN (basetype_path) = TREE_VALUE (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
- BINFO_INHERITANCE_CHAIN (basetype_path) = NULL_TREE;
+ my_friendly_assert (BINFO_INHERITANCE_CHAIN (basetype_path)
+ == NULL_TREE, 980827);
binfo = basetype_path;
type = BINFO_TYPE (binfo);
and we do find NAME in TYPE, verify that such a second
sighting is in fact valid. */
- index = lookup_fnfields_here (type, name);
+ idx = lookup_fnfields_here (type, name);
- if (index >= 0 || (lookup_field_1 (type, name)!=NULL_TREE && !find_all))
+ 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). */
+ 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 (index >= 0)
+ rval_binfo. */
+ if (idx >= 0)
{
- rval = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), index);
+ rval = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), idx);
/* Note, rvals can only be previously set if find_all is
true. */
- rvals = my_tree_cons (basetype_path, rval, rvals);
+ 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), index);
+ TREE_TYPE (rvals) = TREE_VEC_ELT (CLASSTYPE_BASELINK_VEC (type), idx);
}
else
{
- /* Undo finding it before, as something else hides it. */
+ /* Undo finding it before, as something else hides it. */
rval = NULL_TREE;
rvals = NULL_TREE;
}
}
else
{
- /* This is ambiguous. */
+ /* This is ambiguous. */
errstr = "request for method `%D' is ambiguous";
rvals = error_mark_node;
break;
}
search_stack = pop_search_level (search_stack);
- if (entry)
- {
- if (errstr)
- {
- tree error_string = my_build_string (errstr);
- /* Save error message with entry. */
- TREE_TYPE (entry) = error_string;
- }
- else
- {
- /* Mark entry as having no error string. */
- TREE_TYPE (entry) = NULL_TREE;
- TREE_VALUE (entry) = rvals;
- }
- }
-
- if (errstr && protect)
+ if (errstr && protect)
{
cp_error (errstr, name);
rvals = error_mark_node;
return rvals;
}
+
+/* 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. */
+
+tree
+lookup_member (xbasetype, name, protect, want_type)
+ tree xbasetype, name;
+ int protect, want_type;
+{
+ 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;
+}
\f
/* BREADTH-FIRST SEARCH ROUTINES. */
/* Search a multiple inheritance hierarchy by breadth-first search.
- TYPE is an aggregate type, possibly in a multiple-inheritance hierarchy.
+ 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. */
-HOST_WIDE_INT
+static tree
breadth_first_search (binfo, testfn, qfn)
tree binfo;
- int (*testfn)();
- int (*qfn)();
+ tree (*testfn) PROTO((tree));
+ int (*qfn) PROTO((tree));
{
int head = 0, tail = 0;
- int rval = 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);
tree base_binfo = TREE_VEC_ELT (binfos, i);
if (BINFO_MARKED (base_binfo) == 0
- && (qfn == 0 || (*qfn) (binfo, i)))
+ && (qfn == 0 || (*qfn) (base_binfo)))
{
SET_BINFO_MARKED (base_binfo);
- obstack_ptr_grow (&search_obstack, binfo);
- obstack_ptr_grow (&search_obstack, (HOST_WIDE_INT) i);
- tail += 2;
+ obstack_ptr_grow (&search_obstack, base_binfo);
+ ++tail;
if (tail >= search_stack->limit)
my_friendly_abort (100);
}
}
binfo = search_stack->first[head++];
- i = (HOST_WIDE_INT) search_stack->first[head++];
- if (rval = (*testfn) (binfo, i))
+ if ((rval = (*testfn) (binfo)))
break;
- binfo = BINFO_BASETYPE (binfo, i);
}
{
tree *tp = search_stack->first;
while (tp < search_tail)
{
tree binfo = *tp++;
- int i = (HOST_WIDE_INT)(*tp++);
- CLEAR_BINFO_MARKED (BINFO_BASETYPE (binfo, i));
+ CLEAR_BINFO_MARKED (binfo);
}
}
}
/* Functions to use in breadth first searches. */
-typedef tree (*pft)();
-typedef int (*pfi)();
-
-int tree_needs_constructor_p (binfo, i)
- tree binfo;
- int i;
-{
- tree basetype;
- my_friendly_assert (i != 0, 296);
- basetype = BINFO_TYPE (BINFO_BASETYPE (binfo, i));
- return TYPE_NEEDS_CONSTRUCTING (basetype);
-}
+typedef tree (*pfi) PROTO((tree));
static tree declarator;
{
tree fndecl;
- for (fndecl = TREE_VALUE (fields); fndecl; fndecl = DECL_CHAIN (fndecl))
- if (DECL_VINDEX (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, i)
+static tree
+get_virtual_destructor (binfo)
tree binfo;
- int i;
{
tree type = BINFO_TYPE (binfo);
- if (i >= 0)
- type = BINFO_TYPE (TREE_VEC_ELT (BINFO_BASETYPES (binfo), i));
if (TYPE_HAS_DESTRUCTOR (type)
- && DECL_VINDEX (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), 0)))
- return TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), 0);
+ && DECL_VINDEX (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), 1)))
+ return TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), 1);
return 0;
}
-int tree_has_any_destructor_p (binfo, i)
+static int
+tree_has_any_destructor_p (binfo)
tree binfo;
- int i;
{
tree type = BINFO_TYPE (binfo);
- if (i >= 0)
- type = BINFO_TYPE (TREE_VEC_ELT (BINFO_BASETYPES (binfo), i));
return TYPE_NEEDS_DESTRUCTOR (type);
}
+/* Returns > 0 if a function with type DRETTYPE overriding a function
+ with type BRETTYPE is covariant, as defined in [class.virtual].
+
+ Returns 1 if trivial covariance, 2 if non-trivial (requiring runtime
+ adjustment), or -1 if pedantically invalid covariance. */
+
+static int
+covariant_return_p (brettype, drettype)
+ tree brettype, drettype;
+{
+ tree binfo;
+
+ if (TREE_CODE (brettype) == FUNCTION_DECL
+ || TREE_CODE (brettype) == THUNK_DECL)
+ {
+ brettype = TREE_TYPE (TREE_TYPE (brettype));
+ drettype = TREE_TYPE (TREE_TYPE (drettype));
+ }
+ else if (TREE_CODE (brettype) == METHOD_TYPE)
+ {
+ brettype = TREE_TYPE (brettype);
+ drettype = TREE_TYPE (drettype);
+ }
+
+ if (same_type_p (brettype, drettype))
+ return 0;
+
+ if (! (TREE_CODE (brettype) == TREE_CODE (drettype)
+ && (TREE_CODE (brettype) == POINTER_TYPE
+ || TREE_CODE (brettype) == REFERENCE_TYPE)
+ && TYPE_QUALS (brettype) == TYPE_QUALS (drettype)))
+ return 0;
+
+ if (! can_convert (brettype, drettype))
+ return 0;
+
+ brettype = TREE_TYPE (brettype);
+ drettype = TREE_TYPE (drettype);
+
+ /* If not pedantic, allow any standard pointer conversion. */
+ if (! IS_AGGR_TYPE (drettype) || ! IS_AGGR_TYPE (brettype))
+ return -1;
+
+ binfo = get_binfo (brettype, drettype, 1);
+
+ /* If we get an error_mark_node from get_binfo, it already complained,
+ so let's just succeed. */
+ if (binfo == error_mark_node)
+ return 1;
+
+ if (! BINFO_OFFSET_ZEROP (binfo) || TREE_VIA_VIRTUAL (binfo))
+ return 2;
+ return 1;
+}
+
/* Given a class type TYPE, and a function decl FNDECL, look for a
virtual function in TYPE's hierarchy which FNDECL could match as a
virtual function. It doesn't matter which one we find.
DTORP is nonzero if we are looking for a destructor. Destructors
need special treatment because they do not match by name. */
+
tree
get_matching_virtual (binfo, fndecl, dtorp)
tree binfo, fndecl;
int dtorp;
{
tree tmp = NULL_TREE;
+ int i;
+
+ if (TREE_CODE (fndecl) == TEMPLATE_DECL)
+ /* In [temp.mem] we have:
+
+ A specialization of a member function template does not
+ override a virtual function from a base class. */
+ return NULL_TREE;
/* Breadth first search routines start searching basetypes
of TYPE, so we must perform first ply of search here. */
if (dtorp)
{
- if (tree_has_any_destructor_p (binfo, -1))
- tmp = get_virtual_destructor (binfo, -1);
-
- if (tmp)
- return tmp;
-
- tmp = (tree) breadth_first_search (binfo,
- (pfi) get_virtual_destructor,
- tree_has_any_destructor_p);
- return tmp;
+ return breadth_first_search (binfo,
+ get_virtual_destructor,
+ tree_has_any_destructor_p);
}
else
{
for (; baselink; baselink = next_baselink (baselink))
{
- for (tmp = TREE_VALUE (baselink); tmp; tmp = DECL_CHAIN (tmp))
+ tree tmps;
+ for (tmps = TREE_VALUE (baselink); tmps; tmps = OVL_NEXT (tmps))
{
+ tmp = OVL_CURRENT (tmps);
if (! DECL_VINDEX (tmp))
continue;
btypes = TYPE_ARG_TYPES (TREE_TYPE (tmp));
if (instptr_type == NULL_TREE)
{
- if (compparms (TREE_CHAIN (btypes), dtypes, 3))
+ if (compparms (TREE_CHAIN (btypes), dtypes))
/* Caller knows to give error in this case. */
return tmp;
return NULL_TREE;
}
- if ((TYPE_READONLY (TREE_TYPE (TREE_VALUE (btypes)))
- == TYPE_READONLY (instptr_type))
- && compparms (TREE_CHAIN (btypes), TREE_CHAIN (dtypes), 3))
+ if (/* The first parameter is the `this' parameter,
+ which has POINTER_TYPE, and we can therefore
+ safely use TYPE_QUALS, rather than
+ CP_TYPE_QUALS. */
+ (TYPE_QUALS (TREE_TYPE (TREE_VALUE (btypes)))
+ == TYPE_QUALS (instptr_type))
+ && compparms (TREE_CHAIN (btypes), TREE_CHAIN (dtypes)))
{
tree brettype = TREE_TYPE (TREE_TYPE (tmp));
- if (comptypes (brettype, drettype, 1))
+ if (same_type_p (brettype, drettype))
/* OK */;
- else if
- (TREE_CODE (brettype) == TREE_CODE (drettype)
- && (TREE_CODE (brettype) == POINTER_TYPE
- || TREE_CODE (brettype) == REFERENCE_TYPE)
- && comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (brettype)),
- TYPE_MAIN_VARIANT (TREE_TYPE (drettype)),
- 0))
- /* covariant return type */
+ else if ((i = covariant_return_p (brettype, drettype)))
{
- tree b = TREE_TYPE (brettype), d = TREE_TYPE (drettype);
- if (TYPE_MAIN_VARIANT (b) != TYPE_MAIN_VARIANT (d))
- {
- tree binfo = get_binfo (b, d, 1);
- if (binfo != error_mark_node
- && ! BINFO_OFFSET_ZEROP (binfo))
- sorry ("adjusting pointers for covariant returns");
- }
- if (TYPE_READONLY (d) > TYPE_READONLY (b))
- {
- cp_error ("return type of `%#D' adds const", fndecl);
- cp_error_at (" overriding definition as `%#D'",
- tmp);
- }
- else if (TYPE_VOLATILE (d) > TYPE_VOLATILE (b))
+ if (i == 2)
+ sorry ("adjusting pointers for covariant returns");
+
+ if (pedantic && i == -1)
{
- cp_error ("return type of `%#D' adds volatile",
- fndecl);
- cp_error_at (" overriding definition as `%#D'",
- tmp);
+ 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)
- && comptypes (brettype, drettype, 0))
+ && 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 (" with `%#D'", fndecl);
+ cp_error_at (" with `%#D'", fndecl);
}
else if (IDENTIFIER_ERROR_LOCUS (name) == NULL_TREE)
{
- cp_error ("conflicting return type specified for virtual function `%#D'", fndecl);
+ 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;
}
}
- if (tmp)
+ /* If not at the end */
+ if (tmps)
{
best = tmp;
break;
}
}
- if (best == NULL_TREE && warn_overloaded_virtual)
- cp_warning_at ("conflicting specification deriving virtual function `%D'", fndecl);
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. */
+
static tree
get_abstract_virtuals_1 (binfo, do_self, abstract_virtuals)
- tree binfo, abstract_virtuals;
+ tree binfo;
int do_self;
+ tree abstract_virtuals;
{
tree binfos = BINFO_BASETYPES (binfo);
int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
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));
+ 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,
/* 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. */
+
tree
get_abstract_virtuals (type)
tree type;
{
tree vbases;
- tree abstract_virtuals = CLASSTYPE_ABSTRACT_VIRTUALS (type);
+ tree abstract_virtuals = NULL;
- /* First get all from non-virtual bases. */
+ /* First get all from non-virtual bases. */
abstract_virtuals
= get_abstract_virtuals_1 (TYPE_BINFO (type), 1, abstract_virtuals);
{
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))
+ 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);
}
tree type_as_binfo_list;
tree type, name;
{
- int head = 0, tail = 0, index;
+ int head = 0, tail = 0, idx;
tree rval = 0, nval = 0;
tree basetypes = type_as_binfo_list;
tree binfo = TYPE_BINFO (type);
basetypes = search_stack->first[head++];
binfo = TREE_VALUE (basetypes);
type = BINFO_TYPE (binfo);
- index = lookup_fnfields_1 (type, name);
- if (index >= 0)
+ idx = lookup_fnfields_1 (type, name);
+ if (idx >= 0)
{
- nval = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), index);
+ 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), index);
+ TREE_TYPE (rval) = TREE_VEC_ELT (CLASSTYPE_BASELINK_VEC (type), idx);
goto dont_queue;
}
}
\f
/* DEPTH-FIRST SEARCH ROUTINES. */
-/* Assign unique numbers to _CLASSTYPE members of the lattice
- specified by TYPE. The root nodes are marked first; the nodes
- are marked depth-fisrt, left-right. */
-
-static int cid;
-
-/* Matrix implementing a relation from CLASSTYPE X CLASSTYPE => INT.
- Relation yields 1 if C1 <= C2, 0 otherwise. */
-typedef char mi_boolean;
-static mi_boolean *mi_matrix;
-
-/* Type for which this matrix is defined. */
-static tree mi_type;
-
-/* Size of the matrix for indexing purposes. */
-static int mi_size;
-
-/* Return nonzero if class C2 derives from class C1. */
-#define BINFO_DERIVES_FROM(C1, C2) \
- ((mi_matrix+mi_size*(BINFO_CID (C1)-1))[BINFO_CID (C2)-1])
-#define TYPE_DERIVES_FROM(C1, C2) \
- ((mi_matrix+mi_size*(CLASSTYPE_CID (C1)-1))[CLASSTYPE_CID (C2)-1])
-#define BINFO_DERIVES_FROM_STAR(C) \
- (mi_matrix+(BINFO_CID (C)-1))
-
/* This routine converts a pointer to be a pointer of an immediate
base class. The normal convert_pointer_to routine would diagnose
the conversion as ambiguous, under MI code that has the base class
- as an ambiguous base class. */
+ as an ambiguous base class. */
+
static tree
convert_pointer_to_single_level (to_type, expr)
tree to_type, expr;
binfo_of_derived = TYPE_BINFO (TREE_TYPE (TREE_TYPE (expr)));
last = get_binfo (to_type, TREE_TYPE (TREE_TYPE (expr)), 0);
- BINFO_INHERITANCE_CHAIN (last) = binfo_of_derived;
- BINFO_INHERITANCE_CHAIN (binfo_of_derived) = NULL_TREE;
- return build_vbase_path (PLUS_EXPR, build_pointer_type (to_type), expr, last, 1);
+ my_friendly_assert (BINFO_INHERITANCE_CHAIN (last) == binfo_of_derived,
+ 980827);
+ 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. */
+ would be no record. */
+
static void
dfs_walk (binfo, fn, qfn)
tree binfo;
- void (*fn)();
- int (*qfn)();
+ void (*fn) PROTO((tree));
+ int (*qfn) PROTO((tree));
{
tree binfos = BINFO_BASETYPES (binfo);
int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
if (qfn == 0 || (*qfn)(base_binfo))
{
- if (fn == dfs_init_vbase_pointers)
+ 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
/* No need for the conversion here, as we know it is the
right type. */
vbase_decl_ptr_intermediate
- = (tree)CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (base_binfo));
+ = CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (base_binfo));
}
else
{
dfs_walk (base_binfo, fn, qfn);
vbase_decl_ptr_intermediate = saved_vbase_decl_ptr_intermediate;
- } else
- dfs_walk (base_binfo, fn, qfn);
+ }
+ else
+ dfs_walk (base_binfo, fn, qfn);
}
}
fn (binfo);
}
-/* Predicate functions which serve for dfs_walk. */
-static int numberedp (binfo) tree binfo;
-{ return BINFO_CID (binfo); }
-static int unnumberedp (binfo) tree binfo;
-{ return BINFO_CID (binfo) == 0; }
+/* Like dfs_walk, but only walk until fn returns something, and return
+ that. We also use the real vbase binfos instead of the placeholders
+ in the normal binfo hierarchy. START is the most-derived type for this
+ hierarchy, so that we can find the vbase binfos. */
+
+static tree
+dfs_search (binfo, fn, start)
+ tree binfo, start;
+ tree (*fn) PROTO((tree));
+{
+ tree binfos = BINFO_BASETYPES (binfo);
+ int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+ tree retval;
+
+ for (i = 0; i < n_baselinks; i++)
+ {
+ 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);
+}
static int markedp (binfo) tree binfo;
{ return BINFO_MARKED (binfo); }
-static int bfs_markedp (binfo, i) tree binfo; int i;
-{ return BINFO_MARKED (BINFO_BASETYPE (binfo, i)); }
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 marked_vtable_pathp (binfo) tree binfo;
-{ return BINFO_VTABLE_PATH_MARKED (binfo); }
static int bfs_marked_vtable_pathp (binfo, i) tree binfo; int i;
{ return BINFO_VTABLE_PATH_MARKED (BINFO_BASETYPE (binfo, i)); }
-static int unmarked_vtable_pathp (binfo) tree binfo;
-{ return BINFO_VTABLE_PATH_MARKED (binfo) == 0; }
static int bfs_unmarked_vtable_pathp (binfo, i) tree binfo; int i;
{ return BINFO_VTABLE_PATH_MARKED (BINFO_BASETYPE (binfo, i)) == 0; }
-static int marked_new_vtablep (binfo) tree binfo;
-{ return BINFO_NEW_VTABLE_MARKED (binfo); }
static int bfs_marked_new_vtablep (binfo, i) tree binfo; int i;
{ return BINFO_NEW_VTABLE_MARKED (BINFO_BASETYPE (binfo, i)); }
-static int unmarked_new_vtablep (binfo) tree binfo;
-{ return BINFO_NEW_VTABLE_MARKED (binfo) == 0; }
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; }
+#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; }
test anything (vis a vis marking) if they are paired with
a predicate function (above). */
-/* Assign each type within the lattice a number which is unique
- in the lattice. The first number assigned is 1. */
-
-static void
-dfs_number (binfo)
- tree binfo;
-{
- BINFO_CID (binfo) = ++cid;
-}
-
-static void
-dfs_unnumber (binfo)
- tree binfo;
-{
- BINFO_CID (binfo) = 0;
-}
-
+#if 0
static void
dfs_mark (binfo) tree binfo;
{ SET_BINFO_MARKED (binfo); }
+#endif
static void
dfs_unmark (binfo) tree binfo;
{ CLEAR_BINFO_MARKED (binfo); }
+#if 0
static void
dfs_mark_vtable_path (binfo) tree binfo;
{ SET_BINFO_VTABLE_PATH_MARKED (binfo); }
static void
dfs_clear_search_slot (binfo) tree binfo;
{ CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (binfo)) = 0; }
+#endif
static void
dfs_debug_mark (binfo)
CLASSTYPE_DEBUG_REQUESTED (t) = 1;
- /* If interface info is known, the value of (?@@?) is correct. */
- if (methods == 0
- || CLASSTYPE_INTERFACE_KNOWN (t)
- || (write_virtuals == 2 && TYPE_VIRTUAL_P (t)))
+ 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;
/* If debug info is requested from this context for this type, supply it.
if (current_function_decl == NULL_TREE
|| DECL_CLASS_CONTEXT (current_function_decl) != t)
{
- if (TREE_VEC_ELT (methods, 0))
+ 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, 1);
+ methods = TREE_VEC_ELT (methods, 2);
+ methods = OVL_CURRENT (methods);
while (methods)
{
if (DECL_VINDEX (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, global_bindings_p ());
+ rest_of_type_compilation (t, toplevel_bindings_p ());
}
\f
/* Attach to the type of the virtual base class, the pointer to the
virtual base class, given the global pointer vbase_decl_ptr.
We use the global vbase_types. ICK! */
+
static void
dfs_find_vbases (binfo)
tree binfo;
tree binfo = binfo_member (vbase, vbase_types);
CLASSTYPE_SEARCH_SLOT (vbase)
- = (char *) build (PLUS_EXPR, build_pointer_type (vbase),
- vbase_decl_ptr, BINFO_OFFSET (binfo));
+ = build (PLUS_EXPR, build_pointer_type (vbase),
+ vbase_decl_ptr, BINFO_OFFSET (binfo));
}
}
SET_BINFO_VTABLE_PATH_MARKED (binfo);
CLEAR_BINFO_VTABLE_PATH_MARKED (binfo);
- /* If there is a rtti, it is the first field, though perhaps from
- the base class. Otherwise, the first fields are virtual base class
- pointer fields. */
- if (CLASSTYPE_RTTI (type) && VFIELD_NAME_P (DECL_NAME (fields)))
- /* Get past vtable for the object. */
+#if 0
+ /* See finish_struct_1 for when we can enable this. */
+ /* If we have a vtable pointer first, skip it. */
+ if (VFIELD_NAME_P (DECL_NAME (fields)))
fields = TREE_CHAIN (fields);
+#endif
if (fields == NULL_TREE
|| DECL_NAME (fields) == NULL_TREE
{
tree ref = build (COMPONENT_REF, TREE_TYPE (fields),
build_indirect_ref (this_vbase_ptr, NULL_PTR), fields);
- tree init = (tree)CLASSTYPE_SEARCH_SLOT (TREE_TYPE (TREE_TYPE (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),
/* 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)
tree binfo;
tree binfo = TYPE_BINFO (type);
flag_this_is_variable = -2;
vbase_types = CLASSTYPE_VBASECLASSES (type);
- vbase_decl_ptr = decl_ptr;
- vbase_decl = build_indirect_ref (decl_ptr, NULL_PTR);
- vbase_decl_ptr_intermediate = vbase_decl_ptr;
+ 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);
We know that if there is more than one place (binfo) the fndecl that the
declared, they all refer to the same binfo. See get_class_offset_1 for
the check that ensures this. */
+
static tree
virtual_context (fndecl, t, vbase)
tree fndecl, t, vbase;
offset information for the virtual bases, so the offsets are only
calculated once. The offsets are computed by where we think the
vbase should be (as noted by the CLASSTYPE_SEARCH_SLOT) minus where
- the vbase really is. */
+ the vbase really is. */
+
static void
expand_upcast_fixups (binfo, addr, orig_addr, vbase, vbase_addr, t,
vbase_offsets)
delta = purpose_member (vbase, *vbase_offsets);
if (! delta)
{
- delta = (tree)CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (vbase));
+ delta = CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (vbase));
delta = build (MINUS_EXPR, ptrdiff_type_node, delta, vbase_addr);
delta = save_expr (delta);
delta = tree_cons (vbase, delta, *vbase_offsets);
&& current_fndecl != abort_fndecl
&& (vc=virtual_context (current_fndecl, t, vbase)) != vbase)
{
- /* This may in fact need a runtime fixup. */
- tree idx = DECL_VINDEX (current_fndecl);
+ /* This may in fact need a runtime fixup. */
+ tree idx = build_int_2 (n, 0);
tree vtbl = BINFO_VTABLE (binfo);
tree nvtbl = lookup_name (DECL_NAME (vtbl), 0);
tree aref, ref, naref;
|| nvtbl == IDENTIFIER_GLOBAL_VALUE (DECL_NAME (vtbl)))
{
/* Dup it if it isn't in local scope yet. */
- nvtbl = build_decl (VAR_DECL,
- DECL_NAME (vtbl),
- TYPE_MAIN_VARIANT (TREE_TYPE (BINFO_VTABLE (binfo))));
+ nvtbl = build_decl
+ (VAR_DECL, DECL_NAME (vtbl),
+ TYPE_MAIN_VARIANT (TREE_TYPE (vtbl)));
DECL_ALIGN (nvtbl) = MAX (TYPE_ALIGN (double_type_node),
DECL_ALIGN (nvtbl));
TREE_READONLY (nvtbl) = 0;
+ DECL_ARTIFICIAL (nvtbl) = 1;
nvtbl = pushdecl (nvtbl);
init = NULL_TREE;
- cp_finish_decl (nvtbl, init, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
- DECL_VIRTUAL_P (nvtbl) = 1;
- DECL_CONTEXT (nvtbl) = t;
+ cp_finish_decl (nvtbl, init, NULL_TREE, 0,
+ LOOKUP_ONLYCONVERTING);
+
+ /* We don't set DECL_VIRTUAL_P and DECL_CONTEXT on nvtbl
+ because they wouldn't be useful; everything that wants to
+ look at the vtable will look at the decl for the normal
+ vtable. Setting DECL_CONTEXT also screws up
+ decl_function_context. */
+
init = build (MODIFY_EXPR, TREE_TYPE (nvtbl),
nvtbl, vtbl);
TREE_SIDE_EFFECTS (init) = 1;
expand_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 (build_modify_expr (ref, NOP_EXPR,
- build_unary_op (ADDR_EXPR, nvtbl, 0)));
+ /* 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
+ (build_modify_expr (ref, NOP_EXPR, nvtbl));
}
assemble_external (vtbl);
aref = build_array_ref (vtbl, idx);
naref = build_array_ref (nvtbl, idx);
- old_delta = build_component_ref (aref, delta_identifier, 0, 0);
- new_delta = build_component_ref (naref, delta_identifier, 0, 0);
+ old_delta = build_component_ref (aref, delta_identifier,
+ NULL_TREE, 0);
+ new_delta = build_component_ref (naref, delta_identifier,
+ NULL_TREE, 0);
/* This is a upcast, so we have to add the offset for the
virtual base. */
if (! vc_delta)
{
tree vc_addr = convert_pointer_to_real (vc, orig_addr);
- vc_delta = (tree)CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (vc));
+ vc_delta = CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (vc));
vc_delta = build (MINUS_EXPR, ptrdiff_type_node,
vc_delta, vc_addr);
vc_delta = save_expr (vc_delta);
}
TREE_READONLY (new_delta) = 0;
+ TREE_TYPE (new_delta) =
+ 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,
old_delta));
}
/* Fixup upcast offsets for all direct vtables. Patterned after
expand_direct_vtbls_init. */
+
static void
fixup_virtual_upcast_offsets (real_binfo, binfo, init_self, can_elide, addr, orig_addr, type, vbase, vbase_offsets)
- tree real_binfo, binfo, addr, orig_addr, type, vbase, *vbase_offsets;
+ tree real_binfo, binfo;
int init_self, can_elide;
+ tree addr, orig_addr, type, vbase, *vbase_offsets;
{
tree real_binfos = BINFO_BASETYPES (real_binfo);
tree binfos = BINFO_BASETYPES (binfo);
{
tree real_base_binfo = TREE_VEC_ELT (real_binfos, i);
tree base_binfo = TREE_VEC_ELT (binfos, i);
- int is_not_base_vtable =
- i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (real_binfo));
+ int is_not_base_vtable
+ = i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (real_binfo));
if (! TREE_VIA_VIRTUAL (real_base_binfo))
fixup_virtual_upcast_offsets (real_base_binfo, base_binfo,
is_not_base_vtable, can_elide, addr,
offsets are valid to store vtables. When zero, we must store new
vtables through virtual baseclass pointers.
- We setup and use the globals: vbase_decl, vbase_decl_ptr, vbase_types
+ We setup and use the globals: vbase_decl_ptr, vbase_types
ICK! */
void
-expand_indirect_vtbls_init (binfo, true_exp, decl_ptr, use_computed_offsets)
+expand_indirect_vtbls_init (binfo, true_exp, decl_ptr)
tree binfo;
tree true_exp, decl_ptr;
- int use_computed_offsets;
{
tree type = BINFO_TYPE (binfo);
+
+ /* This function executes during the finish_function() segment,
+ AFTER the auto variables and temporary stack space has been marked
+ unused...If space is needed for the virtual function tables,
+ some of them might fit within what the compiler now thinks
+ are available stack slots... These values are actually initialized at
+ the beginnning of the function, so when the automatics use their space,
+ they will overwrite the values that are placed here. Marking all
+ temporary space as unavailable prevents this from happening. */
+
+ mark_all_temps_used();
+
if (TYPE_USES_VIRTUAL_BASECLASSES (type))
{
rtx fixup_insns = NULL_RTX;
- int old_flag = flag_this_is_variable;
tree vbases = CLASSTYPE_VBASECLASSES (type);
vbase_types = vbases;
vbase_decl_ptr = true_exp ? build_unary_op (ADDR_EXPR, true_exp, 0) : decl_ptr;
- vbase_decl = true_exp ? true_exp : build_indirect_ref (decl_ptr, NULL_PTR);
-
- if (use_computed_offsets)
- {
- /* This is an object of type IN_TYPE, */
- flag_this_is_variable = -2;
- }
dfs_walk (binfo, dfs_find_vbases, unmarked_new_vtablep);
for (; vbases; vbases = TREE_CHAIN (vbases))
{
tree addr;
- if (use_computed_offsets)
- addr = (tree)CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (vbases));
- else
- {
-#if 1
- addr = convert_pointer_to_vbase (TREE_TYPE (vbases), vbase_decl_ptr);
-#else
- /* This should should never work better than the above. (mrs) */
- tree vbinfo = get_binfo (TREE_TYPE (vbases),
- TREE_TYPE (vbase_decl),
- 0);
-
- /* See is we can get lucky. */
- if (TREE_VIA_VIRTUAL (vbinfo))
- addr = convert_pointer_to_real (vbinfo, vbase_decl_ptr);
- else
- {
- /* We go through all these contortions to avoid this
- call, as it will fail when the virtual base type
- is ambiguous from here. We don't yet have a way
- to search for and find just an instance of the
- virtual base class. Searching for the binfo in
- vbases won't work, as we don't have the vbase
- pointer field, for all vbases in the main class,
- only direct vbases. */
- addr = convert_pointer_to_real (TREE_TYPE (vbases),
- vbase_decl_ptr);
- if (addr == error_mark_node)
- continue;
- }
-#endif
- }
- /* Do all vtables from this virtual base. */
+ 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 CLASSTPE_VFIELD_PARENT sense) */
+ binfos. (in the CLASSTYPE_VFIELD_PARENT sense) */
expand_direct_vtbls_init (vbases, TYPE_BINFO (BINFO_TYPE (vbases)),
1, 0, addr);
- /* If we are using computed offsets we can skip fixups. */
- if (use_computed_offsets)
- continue;
-
- /* 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. */
+ /* 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. */
+ /* We don't have dynamic thunks yet!
+ So for now, just fail silently. */
}
else
{
}
dfs_walk (binfo, dfs_clear_vbase_slots, marked_new_vtablep);
-
- flag_this_is_variable = old_flag;
}
}
-void
-clear_search_slots (type)
- tree type;
-{
- dfs_walk (TYPE_BINFO (type),
- dfs_clear_search_slot, dfs_search_slot_nonempty_p);
-}
-
/* get virtual base class types.
This adds type to the vbase_types list in reverse dfs order.
Ordering is very important, so don't change it. */
{
if (TREE_VIA_VIRTUAL (binfo) && ! BINFO_VBASE_MARKED (binfo))
{
- vbase_types = make_binfo (integer_zero_node, binfo,
- BINFO_VTABLE (binfo),
- BINFO_VIRTUALS (binfo), vbase_types);
- TREE_VIA_VIRTUAL (vbase_types) = 1;
+ tree new_vbase = make_binfo (integer_zero_node, binfo,
+ BINFO_VTABLE (binfo),
+ BINFO_VIRTUALS (binfo));
+ TREE_CHAIN (new_vbase) = vbase_types;
+ TREE_VIA_VIRTUAL (new_vbase) = 1;
+ vbase_types = new_vbase;
SET_BINFO_VBASE_MARKED (binfo);
}
SET_BINFO_MARKED (binfo);
}
/* get a list of virtual base classes in dfs order. */
+
tree
get_vbase_types (type)
tree type;
tree vbases;
tree binfo;
- if (TREE_CODE (type) == TREE_VEC)
- binfo = type;
- else
- binfo = TYPE_BINFO (type);
-
+ binfo = TYPE_BINFO (type);
vbase_types = NULL_TREE;
dfs_walk (binfo, dfs_get_vbase_types, unmarkedp);
dfs_walk (binfo, dfs_unmark, markedp);
return vbase_types;
}
\f
-static void
-dfs_record_inheritance (binfo)
- tree binfo;
-{
- tree binfos = BINFO_BASETYPES (binfo);
- int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
- mi_boolean *derived_row = BINFO_DERIVES_FROM_STAR (binfo);
-
- for (i = n_baselinks-1; i >= 0; i--)
- {
- int j;
- tree base_binfo = TREE_VEC_ELT (binfos, i);
- tree baseclass = BINFO_TYPE (base_binfo);
- mi_boolean *base_row = BINFO_DERIVES_FROM_STAR (base_binfo);
-
- /* Don't search if there's nothing there! MI_SIZE can be
- zero as a result of parse errors. */
- if (TYPE_BINFO_BASETYPES (baseclass) && mi_size > 0)
- for (j = mi_size*(CLASSTYPE_CID (baseclass)-1); j >= 0; j -= mi_size)
- derived_row[j] |= base_row[j];
- TYPE_DERIVES_FROM (baseclass, BINFO_TYPE (binfo)) = 1;
- }
-
- SET_BINFO_MARKED (binfo);
-}
-
-/* Given a _CLASSTYPE node in a multiple inheritance lattice,
- convert the lattice into a simple relation such that,
- given to CIDs, C1 and C2, one can determine if C1 <= C2
- or C2 <= C1 or C1 <> C2.
-
- Once constructed, we walk the lattice depth fisrt,
- applying various functions to elements as they are encountered.
-
- We use xmalloc here, in case we want to randomly free these tables. */
-
-#define SAVE_MI_MATRIX
-
-void
-build_mi_matrix (type)
- tree type;
-{
- tree binfo = TYPE_BINFO (type);
- cid = 0;
-
-#ifdef SAVE_MI_MATRIX
- if (CLASSTYPE_MI_MATRIX (type))
- {
- mi_size = CLASSTYPE_N_SUPERCLASSES (type) + CLASSTYPE_N_VBASECLASSES (type);
- mi_matrix = CLASSTYPE_MI_MATRIX (type);
- mi_type = type;
- dfs_walk (binfo, dfs_number, unnumberedp);
- return;
- }
-#endif
-
- mi_size = CLASSTYPE_N_SUPERCLASSES (type) + CLASSTYPE_N_VBASECLASSES (type);
- mi_matrix = (char *)xmalloc ((mi_size + 1) * (mi_size + 1));
- mi_type = type;
- bzero (mi_matrix, (mi_size + 1) * (mi_size + 1));
- dfs_walk (binfo, dfs_number, unnumberedp);
- dfs_walk (binfo, dfs_record_inheritance, unmarkedp);
- dfs_walk (binfo, dfs_unmark, markedp);
-}
-
-void
-free_mi_matrix ()
-{
- dfs_walk (TYPE_BINFO (mi_type), dfs_unnumber, numberedp);
-
-#ifdef SAVE_MI_MATRIX
- CLASSTYPE_MI_MATRIX (mi_type) = mi_matrix;
-#else
- free (mi_matrix);
- mi_size = 0;
- cid = 0;
-#endif
-}
-\f
/* 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
tree type;
{
tree field;
+
+ if (current_template_parms)
+ return;
+
+ if (TYPE_BEING_DEFINED (type))
+ /* 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)
+ return;
+
dfs_walk (TYPE_BINFO (type), dfs_debug_mark, dfs_debug_unmarkedp);
for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
{
tree name = DECL_NAME (decl);
int dont_add = 0;
- /* virtual base names are always unique. */
+ /* 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;
warning ("in this context");
}
- context = (TREE_CODE (value) == FUNCTION_DECL
- && DECL_VIRTUAL_P (value))
- ? DECL_CLASS_CONTEXT (value)
- : DECL_CONTEXT (value);
+ context = DECL_REAL_CONTEXT (value);
if (context == type)
{
else
dont_add = 1;
}
- else if (context && TYPE_DERIVES_FROM (context, type))
+ else if (type == current_class_type
+ || DERIVED_FROM_P (context, type))
{
/* Don't add in *values to list */
*values = NULL_TREE;
? DECL_CLASS_CONTEXT (value)
: DECL_CONTEXT (value);
- if (context && TYPE_DERIVES_FROM (context, type))
+ if (type == current_class_type
+ || DERIVED_FROM_P (context, type))
{
/* remove *tmp from list */
*tmp = TREE_CHAIN (*tmp);
}
}
+/* 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. */
+
+static int
+dependent_base_p (binfo)
+ tree binfo;
+{
+ for (; binfo; binfo = BINFO_INHERITANCE_CHAIN (binfo))
+ {
+ if (TREE_TYPE (binfo) == current_class_type)
+ 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
tree binfo;
{
tree type = BINFO_TYPE (binfo);
- tree fields, *methods, *end;
+ tree fields;
tree method_vec;
+ int dummy = 0;
+
+ /* Only record types if we're a template base. */
+ if (processing_template_decl && type != current_class_type
+ && dependent_base_p (binfo))
+ dummy = 1;
for (fields = TYPE_FIELDS (type); fields; fields = TREE_CHAIN (fields))
{
+ 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 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)
}
envelope_add_decl (type, fields, &TREE_PURPOSE (class_value));
+ pop_obstacks ();
}
}
- method_vec = CLASSTYPE_METHOD_VEC (type);
- if (method_vec != 0)
+ 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. */
- methods = &TREE_VEC_ELT (method_vec, 1);
end = TREE_VEC_END (method_vec);
- while (methods != end)
+ 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 = DECL_NAME (*methods);
- tree class_value = IDENTIFIER_CLASS_VALUE (name);
+ tree name;
+ tree class_value;
+
+
+ name = DECL_NAME (OVL_CURRENT (*methods));
+ class_value = IDENTIFIER_CLASS_VALUE (name);
+
+ maybe_push_cache_obstack ();
/* If the class value is not an envelope of the kind described in
the comment above, we create a new envelope. */
/* Here we try to rule out possible ambiguities.
If we can't do that, keep a TREE_LIST with possibly ambiguous
decls in there. */
- maybe_push_cache_obstack ();
- envelope_add_decl (type, *methods, &TREE_PURPOSE (class_value));
+ /* 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 ();
-
- methods++;
}
}
- SET_BINFO_MARKED (binfo);
+
+ /* 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);
}
/* Consolidate unique (by name) member functions. */
+
static void
dfs_compress_decls (binfo)
tree binfo;
{
tree type = BINFO_TYPE (binfo);
- tree method_vec = CLASSTYPE_METHOD_VEC (type);
+ tree method_vec
+ = CLASS_TYPE_P (type) ? CLASSTYPE_METHOD_VEC (type) : NULL_TREE;
- if (method_vec != 0)
+ 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_VEC_ELT (method_vec, 1);
+ tree *methods;
tree *end = TREE_VEC_END (method_vec);
- for (; methods != end; methods++)
+ 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 (*methods));
+ 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
if (TREE_CHAIN (tmp) == NULL_TREE
&& TREE_VALUE (tmp)
- && DECL_CHAIN (TREE_VALUE (tmp)) == NULL_TREE)
+ && OVL_NEXT (TREE_VALUE (tmp)) == NULL_TREE)
{
TREE_PURPOSE (class_value) = TREE_VALUE (tmp);
}
}
}
- CLEAR_BINFO_MARKED (binfo);
+ CLEAR_BINFO_PUSHDECLS_MARKED (binfo);
}
/* When entering the scope of a class, we cache all of the
with `error_mark_node' so that if they are encountered
without explicit qualification, we can emit an error
message. */
+
void
push_class_decls (type)
tree type;
{
- tree id;
struct obstack *ambient_obstack = current_obstack;
-
search_stack = push_search_level (search_stack, &search_obstack);
- id = TYPE_IDENTIFIER (type);
-#if 0
- if (IDENTIFIER_TEMPLATE (id) != 0)
- {
- tree tmpl = IDENTIFIER_TEMPLATE (id);
- push_template_decls (DECL_ARGUMENTS (TREE_PURPOSE (tmpl)),
- TREE_VALUE (tmpl), 1);
- overload_template_name (id, 1);
- }
-#endif
+ /* 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, unmarkedp);
+ 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, markedp);
+ 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. */
{
tree node = TREE_VALUE (new);
- while (TREE_CODE (node) == TREE_LIST)
+ 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);
}
pushdecl_class_level (new);
closed_envelopes = TREE_CHAIN (closed_envelopes);
}
+
+ /* Undo the call to maybe_push_cache_obstack above. */
+ pop_obstacks ();
+
current_obstack = ambient_obstack;
}
/* Here's a subroutine we need because C lacks lambdas. */
+
static void
dfs_unuse_fields (binfo)
tree binfo;
}
void
-pop_class_decls (type)
- tree type;
+pop_class_decls ()
{
/* We haven't pushed a search level when dealing with cached classes,
so we'd better not try to pop it. */
print_search_statistics ()
{
#ifdef GATHER_STATISTICS
- if (flag_memoize_lookups)
- {
- fprintf (stderr, "%d memoized contexts saved\n",
- n_contexts_saved);
- fprintf (stderr, "%d local tree nodes made\n", my_tree_node_counter);
- fprintf (stderr, "%d local hash nodes made\n", my_memoized_entry_counter);
- fprintf (stderr, "fields statistics:\n");
- fprintf (stderr, " memoized finds = %d; rejects = %d; (searches = %d)\n",
- memoized_fast_finds[0], memoized_fast_rejects[0],
- memoized_fields_searched[0]);
- fprintf (stderr, " memoized_adds = %d\n", memoized_adds[0]);
- fprintf (stderr, "fnfields statistics:\n");
- fprintf (stderr, " memoized finds = %d; rejects = %d; (searches = %d)\n",
- memoized_fast_finds[1], memoized_fast_rejects[1],
- memoized_fields_searched[1]);
- fprintf (stderr, " memoized_adds = %d\n", memoized_adds[1]);
- }
fprintf (stderr, "%d fields searched in %d[%d] calls to lookup_field[_1]\n",
n_fields_searched, n_calls_lookup_field, n_calls_lookup_field_1);
fprintf (stderr, "%d fnfields searched in %d calls to lookup_fnfields\n",
n_outer_fields_searched, n_calls_lookup_fnfields);
fprintf (stderr, "%d calls to get_base_type\n", n_calls_get_base_type);
-#else
+#else /* GATHER_STATISTICS */
fprintf (stderr, "no search statistics\n");
-#endif
+#endif /* GATHER_STATISTICS */
}
void
init_search_processing ()
{
gcc_obstack_init (&search_obstack);
- gcc_obstack_init (&type_obstack);
- gcc_obstack_init (&type_obstack_entries);
-
- /* This gives us room to build our chains of basetypes,
- whether or not we decide to memoize them. */
- type_stack = push_type_level (0, &type_obstack);
_vptr_name = get_identifier ("_vptr");
}
void
reinit_search_statistics ()
{
- my_memoized_entry_counter = 0;
- memoized_fast_finds[0] = 0;
- memoized_fast_finds[1] = 0;
- memoized_adds[0] = 0;
- memoized_adds[1] = 0;
- memoized_fast_rejects[0] = 0;
- memoized_fast_rejects[1] = 0;
- memoized_fields_searched[0] = 0;
- memoized_fields_searched[1] = 0;
+#ifdef GATHER_STATISTICS
n_fields_searched = 0;
n_calls_lookup_field = 0, n_calls_lookup_field_1 = 0;
n_calls_lookup_fnfields = 0, n_calls_lookup_fnfields_1 = 0;
n_calls_get_base_type = 0;
n_outer_fields_searched = 0;
n_contexts_saved = 0;
+#endif /* GATHER_STATISTICS */
}
+#define scratch_tree_cons expr_tree_cons
+
static tree conversions;
-static void
+static tree
add_conversions (binfo)
tree binfo;
{
int i;
- tree vec = CLASSTYPE_METHOD_VEC (BINFO_TYPE (binfo));
+ tree method_vec = CLASSTYPE_METHOD_VEC (BINFO_TYPE (binfo));
- for (i = 1; i < TREE_VEC_LENGTH (vec); ++i)
+ for (i = 2; i < TREE_VEC_LENGTH (method_vec); ++i)
{
- tree tmp = TREE_VEC_ELT (vec, i);
- if (! IDENTIFIER_TYPENAME_P (DECL_NAME (tmp)))
+ tree tmp = TREE_VEC_ELT (method_vec, i);
+ tree name;
+
+ if (!tmp || ! DECL_CONV_FN_P (OVL_CURRENT (tmp)))
break;
- conversions = tree_cons (DECL_NAME (tmp), TREE_TYPE (TREE_TYPE (tmp)),
- conversions);
+
+ name = DECL_NAME (OVL_CURRENT (tmp));
+
+ /* Make sure we don't already have this conversion. */
+ if (! IDENTIFIER_MARKED (name))
+ {
+ conversions = scratch_tree_cons (binfo, tmp, conversions);
+ IDENTIFIER_MARKED (name) = 1;
+ }
}
+ return NULL_TREE;
}
tree
lookup_conversions (type)
tree type;
{
+ tree t;
+
conversions = NULL_TREE;
- dfs_walk (TYPE_BINFO (type), add_conversions, 0);
+
+ if (TYPE_SIZE (type))
+ breadth_first_search (TYPE_BINFO (type), add_conversions, 0);
+
+ for (t = conversions; t; t = TREE_CHAIN (t))
+ 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;
+{
+ 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;
+}
+
+/* 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)
+ tree empty_binfo;
+{
+ tree binfo;
+ for (binfo = TYPE_BINFO (compare_type); ; binfo = BINFO_BASETYPE (binfo, 0))
+ {
+ if (BINFO_TYPE (binfo) == BINFO_TYPE (empty_binfo))
+ {
+ found_overlap = 1;
+ break;
+ }
+ else if (BINFO_BASETYPES (binfo) == NULL_TREE)
+ break;
+ }
+}
+
+/* Trivial function to stop base traversal when we find something. */
+
+static int
+dfs_no_overlap_yet (t)
+ tree t ATTRIBUTE_UNUSED;
+{
+ return found_overlap == 0;
+}
+
+/* Returns nonzero if EMPTY_TYPE or any of its bases can also be found at
+ offset 0 in NEXT_TYPE. Used in laying out empty base class subobjects. */
+
+int
+types_overlap_p (empty_type, next_type)
+ tree empty_type, next_type;
+{
+ 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;
+}
+
+/* Passed to dfs_search by binfo_for_vtable; determine if bvtable comes
+ from BINFO. */
+
+static tree bvtable;
+static tree
+dfs_bfv_helper (binfo)
+ tree binfo;
+{
+ if (BINFO_VTABLE (binfo) == bvtable)
+ return binfo;
+ return NULL_TREE;
+}
+
+/* Given a vtable VARS, determine which binfo it comes from. */
+
+tree
+binfo_for_vtable (vars)
+ tree vars;
+{
+ bvtable = vars;
+ return dfs_search (TYPE_BINFO (DECL_CONTEXT (vars)), dfs_bfv_helper,
+ DECL_CONTEXT (vars));
+}