aboutsummaryrefslogtreecommitdiff
path: root/gnu/usr.bin/cc/cc1plus/cp-search.c
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/usr.bin/cc/cc1plus/cp-search.c')
-rw-r--r--gnu/usr.bin/cc/cc1plus/cp-search.c4284
1 files changed, 4284 insertions, 0 deletions
diff --git a/gnu/usr.bin/cc/cc1plus/cp-search.c b/gnu/usr.bin/cc/cc1plus/cp-search.c
new file mode 100644
index 000000000000..9f3e0a5a1549
--- /dev/null
+++ b/gnu/usr.bin/cc/cc1plus/cp-search.c
@@ -0,0 +1,4284 @@
+/* Breadth-first and depth-first routines for
+ searching multiple-inheritance lattice for GNU C++.
+ Copyright (C) 1987, 1989, 1992, 1993 Free Software Foundation, Inc.
+ Contributed by Michael Tiemann (tiemann@cygnus.com)
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if 0
+/* Remove before release, should only appear for development and testing. */
+#define CHECK_convert_pointer_to_single_level
+#endif
+
+/* High-level class interface. */
+
+#include "config.h"
+#include "tree.h"
+#include <stdio.h>
+#include "cp-tree.h"
+#include "obstack.h"
+#include "flags.h"
+
+#define obstack_chunk_alloc xmalloc
+#define obstack_chunk_free free
+
+void init_search ();
+extern struct obstack *current_obstack;
+
+#include "stack.h"
+
+/* Obstack used for remembering decision points of breadth-first. */
+static struct obstack search_obstack;
+
+/* Obstack used to bridge from one function context to another. */
+static struct obstack bridge_obstack;
+
+/* Methods for pushing and popping objects to and from obstacks. */
+
+struct stack_level *
+push_stack_level (obstack, tp, size)
+ struct obstack *obstack;
+ char *tp; /* Sony NewsOS 5.0 compiler doesn't like void * here. */
+ int size;
+{
+ struct stack_level *stack;
+ /* FIXME. Doesn't obstack_grow, in the case when the current chunk has
+ insufficient space, move the base so that obstack_next_free is not
+ valid? Perhaps obstack_copy should be used rather than obstack_grow,
+ and its returned value be used. -- Raeburn
+ */
+ stack = (struct stack_level *) obstack_next_free (obstack);
+ obstack_grow (obstack, tp, size);
+ obstack_finish (obstack);
+ stack->obstack = obstack;
+ stack->first = (tree *) obstack_base (obstack);
+ stack->limit = obstack_room (obstack) / sizeof (tree *);
+ return stack;
+}
+
+struct stack_level *
+pop_stack_level (stack)
+ struct stack_level *stack;
+{
+ struct stack_level *tem = stack;
+ struct obstack *obstack = tem->obstack;
+ stack = tem->prev;
+ obstack_free (obstack, tem);
+ return stack;
+}
+
+#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 vbase_types;
+static tree vbase_decl, vbase_decl_ptr;
+static tree vbase_decl_ptr_intermediate;
+static tree vbase_init_result;
+
+/* Allocate a level of searching. */
+static struct search_level *
+push_search_level (stack, obstack)
+ struct stack_level *stack;
+ struct obstack *obstack;
+{
+ struct search_level tem;
+ tem.prev = stack;
+
+ return push_stack_level (obstack, (char *) &tem, sizeof (tem));
+}
+
+/* Discard a level of search allocation. */
+#define pop_search_level pop_stack_level
+
+/* 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];
+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;
+
+/* 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;
+}
+
+/* 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 (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 a visibility 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;
+}
+
+/* This can go away when the new searching strategy as a little mileage on it. */
+#define NEW_SEARCH 1
+#if NEW_SEARCH
+/* This is the newer recursive depth first one, the old one follows. */
+static tree
+get_binfo_recursive (binfo, is_private, parent, rval, rval_private_ptr, xtype,
+ friends, protect)
+ tree binfo, parent, rval, xtype, friends;
+ int *rval_private_ptr, protect, is_private;
+{
+ tree binfos;
+ int i, n_baselinks;
+
+ if (BINFO_TYPE (binfo) == parent)
+ {
+ if (rval == NULL_TREE)
+ {
+ rval = binfo;
+ *rval_private_ptr = is_private;
+ }
+ else
+ {
+ /* I believe it is the case that this error is only an error
+ when used by someone that wants error messages printed.
+ Routines that call this one, that don't set protect want
+ the first one found, even if there are more. */
+ if (protect)
+ {
+ /* Found two or more possible return values. */
+ error_with_aggr_type (parent, "type `%s' is ambiguous base class for type `%s'",
+ TYPE_NAME_STRING (xtype));
+ rval = error_mark_node;
+ }
+ }
+ return rval;
+ }
+
+ 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);
+
+ if (BINFO_MARKED (base_binfo) == 0)
+ {
+ int via_private = is_private || !TREE_VIA_PUBLIC (base_binfo);
+
+ SET_BINFO_MARKED (base_binfo);
+
+ if (via_private == 0)
+ ;
+ else if (protect == 0)
+ via_private = 0;
+ else if (protect == 1 && BINFO_TYPE (binfo) == current_class_type)
+ /* The immediate base class of the class we are in
+ does let its public members through. */
+ via_private = 0;
+#ifndef NOJJG
+ else if (protect
+ && friends != NULL_TREE
+ && BINFO_TYPE (binfo) == xtype
+ && value_member (current_class_type, friends))
+ /* Friend types of the most derived type have access
+ to its baseclass pointers. */
+ via_private = 0;
+#endif
+
+ rval = get_binfo_recursive (base_binfo, via_private, parent, rval,
+ rval_private_ptr, xtype, friends,
+ protect);
+ if (rval == error_mark_node)
+ return rval;
+ }
+ }
+
+ return rval;
+}
+
+/* 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.
+
+ Otherwise, if TYPE is derived from PARENT, return the actual base
+ information, unless a one of the protection violations below
+ occurs, in which case emit an error message and return error_mark_node.
+
+ The below should be worded better. It may not be exactly what the code
+ does, but there should be a lose correlation. If you understand the code
+ well, please try and make the comments below more readable.
+
+ If PROTECT is 1, then check if access to a public field of PARENT
+ would be private.
+
+ If PROTECT is 2, then check if the given type is derived from
+ PARENT via private visibility rules.
+
+ If PROTECT is 3, then immediately private baseclass is ok,
+ but deeper than that, check if private. */
+tree
+get_binfo (parent, binfo, protect)
+ register tree parent, binfo;
+ int protect;
+{
+ tree xtype, type;
+ tree otype;
+ int head = 0, tail = 0;
+ int is_private = 0;
+ tree rval = NULL_TREE;
+ int rval_private = 0;
+ tree friends;
+
+#ifdef GATHER_STATISTICS
+ n_calls_get_base_type++;
+#endif
+
+ if (TREE_CODE (parent) == TREE_VEC)
+ parent = BINFO_TYPE (parent);
+ /* unions cannot participate in inheritance relationships */
+ else if (TREE_CODE (parent) == UNION_TYPE)
+ return NULL_TREE;
+ else if (TREE_CODE (parent) != RECORD_TYPE)
+ my_friendly_abort (89);
+
+ parent = TYPE_MAIN_VARIANT (parent);
+
+ if (TREE_CODE (binfo) == TREE_VEC)
+ type = BINFO_TYPE (binfo);
+ else if (TREE_CODE (binfo) == RECORD_TYPE)
+ {
+ type = binfo;
+ binfo = TYPE_BINFO (type);
+ }
+ else my_friendly_abort (90);
+ xtype = type;
+ friends = current_class_type ? CLASSTYPE_FRIEND_CLASSES (type) : NULL_TREE;
+
+ rval = get_binfo_recursive (binfo, is_private, parent, rval, &rval_private,
+ xtype, friends, protect);
+
+ dfs_walk (binfo, dfs_unmark, markedp);
+
+ if (rval && protect && rval_private)
+ {
+ if (protect == 3)
+ {
+ tree binfos = BINFO_BASETYPES (TYPE_BINFO (xtype));
+ 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))
+ /* It's ok, since it's immediate. */
+ return rval;
+ }
+ }
+ error_with_aggr_type (xtype, "type `%s' is derived from private `%s'",
+ TYPE_NAME_STRING (parent));
+ return error_mark_node;
+ }
+
+ return rval;
+}
+#else
+/* 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.
+
+ Otherwise, if TYPE is derived from PARENT, return the actual base
+ information, unless a one of the protection violations below
+ occurs, in which case emit an error message and return error_mark_node.
+
+ The below should be worded better. It may not be exactly what the code
+ does, but there should be a lose correlation. If you understand the code
+ well, please try and make the comments below more readable.
+
+ If PROTECT is 1, then check if access to a public field of PARENT
+ would be private.
+
+ If PROTECT is 2, then check if the given type is derived from
+ PARENT via private visibility rules.
+
+ If PROTECT is 3, then immediately private baseclass is ok,
+ but deeper than that, check if private. */
+tree
+get_binfo (parent, binfo, protect)
+ register tree parent, binfo;
+ int protect;
+{
+ tree xtype, type;
+ tree otype;
+ int head = 0, tail = 0;
+ int is_private = 0;
+ tree rval = NULL_TREE;
+ int rval_private = 0;
+ tree friends;
+
+#ifdef GATHER_STATISTICS
+ n_calls_get_base_type++;
+#endif
+
+ if (TREE_CODE (parent) == TREE_VEC)
+ parent = BINFO_TYPE (parent);
+ /* unions cannot participate in inheritance relationships */
+ else if (TREE_CODE (parent) == UNION_TYPE)
+ return NULL_TREE;
+ else if (TREE_CODE (parent) != RECORD_TYPE)
+ my_friendly_abort (89);
+
+ parent = TYPE_MAIN_VARIANT (parent);
+ search_stack = push_search_level (search_stack, &search_obstack);
+
+ if (TREE_CODE (binfo) == TREE_VEC)
+ type = BINFO_TYPE (binfo);
+ else if (TREE_CODE (binfo) == RECORD_TYPE)
+ {
+ type = binfo;
+ binfo = TYPE_BINFO (type);
+ }
+ else my_friendly_abort (90);
+ xtype = type;
+ friends = current_class_type ? CLASSTYPE_FRIEND_CLASSES (type) : NULL_TREE;
+
+ while (1)
+ {
+ tree binfos = BINFO_BASETYPES (binfo);
+ int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+
+ /* Process and/or queue base types. */
+ for (i = 0; i < n_baselinks; i++)
+ {
+ tree base_binfo = TREE_VEC_ELT (binfos, i);
+
+ if (BINFO_MARKED (base_binfo) == 0)
+ {
+ int via_private = is_private || !TREE_VIA_PUBLIC (base_binfo);
+
+ SET_BINFO_MARKED (base_binfo);
+
+ if (via_private == 0)
+ ;
+ else if (protect == 0)
+ via_private = 0;
+ else if (protect == 1 && BINFO_TYPE (binfo) == current_class_type)
+ /* The immediate base class of the class we are in
+ does let its public members through. */
+ via_private = 0;
+#ifndef NOJJG
+ else if (protect
+ && friends != NULL_TREE
+ && BINFO_TYPE (binfo) == xtype
+ && value_member (current_class_type, friends))
+ /* Friend types of the most derived type have access
+ to its baseclass pointers. */
+ via_private = 0;
+#endif
+
+ otype = type;
+ obstack_ptr_grow (&search_obstack, base_binfo);
+ obstack_ptr_grow (&search_obstack, (void *) via_private);
+ tail += 2;
+ if (tail >= search_stack->limit)
+ my_friendly_abort (91);
+ }
+#if 0
+ /* This code cannot possibly be right. Ambiguities can only be
+ checked by traversing the whole tree, and seeing if it pops
+ up twice. */
+ else if (protect && ! TREE_VIA_VIRTUAL (base_binfo))
+ {
+ error_with_aggr_type (parent, "type `%s' is ambiguous base class for type `%s'",
+ TYPE_NAME_STRING (xtype));
+ error ("(base class for types `%s' and `%s')",
+ TYPE_NAME_STRING (BINFO_TYPE (binfo)),
+ TYPE_NAME_STRING (otype));
+ rval = error_mark_node;
+ goto cleanup;
+ }
+#endif
+ }
+
+ dont_queue:
+ /* Process head of queue, if one exists. */
+ if (head >= tail)
+ break;
+
+ binfo = search_stack->first[head++];
+ is_private = (int) search_stack->first[head++];
+ if (BINFO_TYPE (binfo) == parent)
+ {
+ if (rval == 0)
+ {
+ rval = binfo;
+ rval_private = is_private;
+ }
+ else
+ /* I believe it is the case that this error is only an error when
+ used by someone that wants error messages printed. Routines that
+ call this one, that don't set protect want the first one found,
+ even if there are more. */
+ if (protect)
+ {
+ /* Found two or more possible return values. */
+ error_with_aggr_type (parent, "type `%s' is ambiguous base class for type `%s'",
+ TYPE_NAME_STRING (xtype));
+ rval = error_mark_node;
+ goto cleanup;
+ }
+ goto dont_queue;
+ }
+ }
+
+ cleanup:
+ {
+ tree *tp = search_stack->first;
+ tree *search_tail = tp + tail;
+
+ while (tp < search_tail)
+ {
+ CLEAR_BINFO_MARKED (*tp);
+ tp += 2;
+ }
+ }
+ search_stack = pop_search_level (search_stack);
+
+ if (rval == error_mark_node)
+ return error_mark_node;
+
+ if (rval && protect && rval_private)
+ {
+ if (protect == 3)
+ {
+ tree binfos = BINFO_BASETYPES (TYPE_BINFO (xtype));
+ 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))
+ /* It's ok, since it's immediate. */
+ return rval;
+ }
+ }
+ error_with_aggr_type (xtype, "type `%s' is derived from private `%s'",
+ TYPE_NAME_STRING (parent));
+ return error_mark_node;
+ }
+
+ return rval;
+}
+#endif
+
+#if NEW_SEARCH
+/* This is the newer depth first get_base_distance, the older one follows. */
+static
+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;
+{
+ tree binfos;
+ int i, n_baselinks;
+
+ if (BINFO_TYPE (binfo) == parent)
+ {
+ if (rval == -1)
+ {
+ 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));
+
+ 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)
+ {
+ /* Note, this should probably succeed to find, and
+ override the old one if the old one was private and
+ this one isn't. */
+ return rval;
+ }
+
+ rval = -2;
+ }
+ return rval;
+ }
+
+ binfos = BINFO_BASETYPES (binfo);
+ n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+ depth += 1;
+
+ /* Process base types. */
+ for (i = 0; i < n_baselinks; i++)
+ {
+ tree base_binfo = TREE_VEC_ELT (binfos, i);
+
+ if (BINFO_MARKED (base_binfo) == 0)
+ {
+ int via_private = is_private || !TREE_VIA_PUBLIC (base_binfo);
+ int was;
+
+ /* When searching for a non-virtual, we cannot mark
+ virtually found binfos. */
+ if (!via_virtual)
+ SET_BINFO_MARKED (base_binfo);
+
+ if (via_private == 0)
+ ;
+ else if (protect == 0)
+ via_private = 0;
+
+#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,
+ TREE_VIA_VIRTUAL (base_binfo)|via_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;
+
+#undef WATCH_VALUES
+
+ }
+ }
+
+ 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.
+
+ Return -1 if TYPE is not derived from PARENT.
+ Return -2 if PARENT is an ambiguous base class of TYPE.
+ Return -3 if PARENT is private to TYPE, and protect is non-zero.
+
+ If PATH_PTR is non-NULL, then also build the list of types
+ from PARENT to TYPE, with TREE_VIA_VIRUAL and TREE_VIA_PUBLIC
+ set.
+
+ It is unclear whether or not the path should be built if -2 and/or
+ -3 is returned. Maybe, maybe not. I suspect that there is code
+ that relies upon it being built, such as prepare_fresh_vtable.
+ (mrs)
+
+ Also, it would appear that we only sometimes want -2. The question is
+ under what exact conditions do we want to see -2, and when do we not
+ want to see -2. (mrs)
+
+ It is also unlikely that this thing finds all ambiguties, as I
+ don't trust any deviation from the method used in get_binfo. It
+ would be nice to use that method here, as it is simple and straight
+ forward. The code here and in recursive_bounded_basetype_p is not.
+ For now, I shall include an extra call to find ambiguities. (mrs)
+ */
+
+int
+get_base_distance (parent, binfo, protect, path_ptr)
+ register tree parent, binfo;
+ int protect;
+ tree *path_ptr;
+{
+ int head, tail;
+ int is_private = 0;
+ int rval = -1;
+ int depth = 0;
+ int rval_private = 0;
+ tree type, basetype_path;
+ tree friends;
+ int use_leftmost;
+ tree new_binfo;
+ int via_virtual;
+
+ if (TYPE_READONLY (parent) || TYPE_VOLATILE (parent))
+ parent = TYPE_MAIN_VARIANT (parent);
+ use_leftmost = (parent == TYPE_MAIN_VARIANT (parent));
+
+ if (TREE_CODE (binfo) == TREE_VEC)
+ type = BINFO_TYPE (binfo);
+ else if (TREE_CODE (binfo) == RECORD_TYPE)
+ {
+ type = binfo;
+ binfo = TYPE_BINFO (type);
+ }
+ else my_friendly_abort (92);
+
+ friends = current_class_type ? CLASSTYPE_FRIEND_CLASSES (type) : NULL_TREE;
+
+ if (path_ptr)
+ {
+ basetype_path = TYPE_BINFO (type);
+ BINFO_INHERITANCE_CHAIN (basetype_path) = NULL_TREE;
+ }
+
+ if (TYPE_MAIN_VARIANT (parent) == type)
+ {
+ /* If the distance is 0, then we don't really need
+ a path pointer, but we shouldn't let garbage go back. */
+ if (path_ptr)
+ *path_ptr = basetype_path;
+ return 0;
+ }
+
+ rval = get_base_distance_recursive (binfo, 0, 0, NULL_TREE, rval,
+ &rval_private, &new_binfo, parent,
+ path_ptr, protect, &via_virtual, 0);
+
+ if (path_ptr)
+ BINFO_INHERITANCE_CHAIN (binfo) = NULL_TREE;
+
+ basetype_path = binfo;
+
+ dfs_walk (binfo, dfs_unmark, markedp);
+
+ binfo = new_binfo;
+
+ /* Visibilities don't count if we found an ambiguous basetype. */
+ if (rval == -2)
+ rval_private = 0;
+
+ if (rval && protect && rval_private)
+ return -3;
+
+ if (path_ptr)
+ *path_ptr = binfo;
+ return rval;
+}
+#else
+/* Recursively search for a path from PARENT to BINFO.
+ If RVAL is > 0 and we succeed, update the BINFO_INHERITANCE_CHAIN
+ pointers.
+ If we find a distinct basetype that's not the one from BINFO,
+ return -2;
+ If we don't find any path, return 0.
+
+ If we encounter a virtual basetype on the path, return RVAL
+ and don't change any pointers after that point. */
+static int
+recursive_bounded_basetype_p (parent, binfo, rval, update_chain)
+ tree parent, binfo;
+ int rval;
+ int update_chain;
+{
+ tree binfos;
+
+ if (BINFO_TYPE (parent) == BINFO_TYPE (binfo))
+ {
+ if (tree_int_cst_equal (BINFO_OFFSET (parent), BINFO_OFFSET (binfo)))
+ return rval;
+ return -2;
+ }
+
+ if (TREE_VIA_VIRTUAL (binfo))
+ update_chain = 0;
+
+ if (binfos = BINFO_BASETYPES (binfo))
+ {
+ int i, nval;
+ for (i = 0; i < TREE_VEC_LENGTH (binfos); i++)
+ {
+ nval = recursive_bounded_basetype_p (parent, TREE_VEC_ELT (binfos, i),
+ rval, update_chain);
+ if (nval < 0)
+ return nval;
+ if (nval > 0 && update_chain)
+ BINFO_INHERITANCE_CHAIN (TREE_VEC_ELT (binfos, i)) = binfo;
+ }
+ return rval;
+ }
+ return 0;
+}
+
+/* -------------------------------------------------- */
+/* These two routines are ONLY here to check for ambiguities for
+ get_base_distance, as it probably cannot check by itself for
+ all ambiguities. When get_base_distance is sure to check for all,
+ these routines can go. (mrs) */
+
+static tree
+get_binfo2_recursive (binfo, parent, type)
+ register tree binfo, parent;
+ tree type;
+{
+ tree rval = NULL_TREE;
+ tree nrval;
+ tree binfos = BINFO_BASETYPES (binfo);
+ int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+
+ if (BINFO_TYPE (binfo) == parent)
+ {
+ return binfo;
+ }
+
+ /* Process base types. */
+ for (i = 0; i < n_baselinks; i++)
+ {
+ tree base_binfo = TREE_VEC_ELT (binfos, i);
+
+ if (BINFO_MARKED (base_binfo) == 0)
+ {
+ SET_BINFO_MARKED (base_binfo);
+
+ nrval = get_binfo2_recursive (base_binfo, parent, type);
+
+ if (nrval == error_mark_node)
+ return nrval;
+ if (nrval)
+ if (rval == 0)
+ {
+ rval = nrval;
+ }
+ else
+ return error_mark_node;
+ }
+ }
+ return rval;
+}
+
+static tree
+get_binfo2 (parent, binfo)
+ register tree parent, binfo;
+{
+ tree type;
+ tree rval = NULL_TREE;
+
+ if (TREE_CODE (parent) == TREE_VEC)
+ parent = BINFO_TYPE (parent);
+ /* unions cannot participate in inheritance relationships */
+ else if (TREE_CODE (parent) == UNION_TYPE)
+ return 0;
+ else if (TREE_CODE (parent) != RECORD_TYPE)
+ my_friendly_abort (89);
+
+ parent = TYPE_MAIN_VARIANT (parent);
+
+ if (TREE_CODE (binfo) == TREE_VEC)
+ type = BINFO_TYPE (binfo);
+ else if (TREE_CODE (binfo) == RECORD_TYPE)
+ {
+ type = binfo;
+ binfo = TYPE_BINFO (type);
+ }
+ else my_friendly_abort (90);
+
+ rval = get_binfo2_recursive (binfo, parent, type);
+
+ dfs_walk (binfo, dfs_unmark, markedp);
+
+ return rval;
+}
+
+/* -------------------------------------------------- */
+
+/* Return the number of levels between type PARENT and the type given
+ in BINFO, following the leftmost path to PARENT. If PARENT is its
+ own main type variant, then if PARENT appears in different places
+ from TYPE's point of view, the leftmost PARENT will be the one
+ chosen.
+
+ Return -1 if TYPE is not derived from PARENT.
+ Return -2 if PARENT is an ambiguous base class of TYPE.
+ Return -3 if PARENT is private to TYPE, and protect is non-zero.
+
+ If PATH_PTR is non-NULL, then also build the list of types
+ from PARENT to TYPE, with TREE_VIA_VIRUAL and TREE_VIA_PUBLIC
+ set.
+
+ It is unclear whether or not the path should be built if -2 and/or
+ -3 is returned. Maybe, maybe not. I suspect that there is code
+ that relies upon it being built, such as prepare_fresh_vtable.
+ (mrs)
+
+ Also, it would appear that we only sometimes want -2. The question is
+ under what exact conditions do we want to see -2, and when do we not
+ want to see -2. (mrs)
+
+ It is also unlikely that this thing finds all ambiguties, as I
+ don't trust any deviation from the method used in get_binfo. It
+ would be nice to use that method here, as it is simple and straight
+ forward. The code here and in recursive_bounded_basetype_p is not.
+ For now, I shall include an extra call to find ambiguities. (mrs)
+ */
+
+int
+get_base_distance (parent, binfo, protect, path_ptr)
+ register tree parent, binfo;
+ int protect;
+ tree *path_ptr;
+{
+ int head, tail;
+ int is_private = 0;
+ int rval = -1;
+ int depth = 0;
+ int rval_private = 0;
+ tree type, basetype_path;
+ tree friends;
+ int use_leftmost;
+
+ if (TYPE_READONLY (parent) || TYPE_VOLATILE (parent))
+ parent = TYPE_MAIN_VARIANT (parent);
+ use_leftmost = (parent == TYPE_MAIN_VARIANT (parent));
+
+ if (TREE_CODE (binfo) == TREE_VEC)
+ type = BINFO_TYPE (binfo);
+ else if (TREE_CODE (binfo) == RECORD_TYPE)
+ {
+ type = binfo;
+ binfo = TYPE_BINFO (type);
+ }
+ else if (TREE_CODE (binfo) == UNION_TYPE)
+ {
+ /* UNION_TYPEs do not participate in inheritance relationships. */
+ return -1;
+ }
+ else my_friendly_abort (92);
+
+ friends = current_class_type ? CLASSTYPE_FRIEND_CLASSES (type) : NULL_TREE;
+
+ if (path_ptr)
+ {
+ basetype_path = TYPE_BINFO (type);
+ BINFO_INHERITANCE_CHAIN (basetype_path) = NULL_TREE;
+ }
+
+ if (TYPE_MAIN_VARIANT (parent) == type)
+ {
+ /* If the distance is 0, then we don't really need
+ a path pointer, but we shouldn't let garbage go back. */
+ if (path_ptr)
+ *path_ptr = basetype_path;
+ return 0;
+ }
+
+ search_stack = push_search_level (search_stack, &search_obstack);
+
+ /* Keep space for TYPE. */
+ obstack_ptr_grow (&search_obstack, binfo);
+ obstack_ptr_grow (&search_obstack, NULL_PTR);
+ obstack_ptr_grow (&search_obstack, NULL_PTR);
+ if (path_ptr)
+ {
+ obstack_ptr_grow (&search_obstack, NULL_PTR);
+ head = 4;
+ }
+ else head = 3;
+ tail = head;
+
+ while (1)
+ {
+ tree binfos = BINFO_BASETYPES (binfo);
+ int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+
+ /* Process and/or queue base types. */
+ for (i = 0; i < n_baselinks; i++)
+ {
+ tree base_binfo = TREE_VEC_ELT (binfos, i);
+
+ if (BINFO_MARKED (base_binfo) == 0)
+ {
+ int via_private = is_private || !TREE_VIA_PUBLIC (base_binfo);
+
+ SET_BINFO_MARKED (base_binfo);
+
+ if (via_private == 0)
+ ;
+ else if (protect == 0)
+ via_private = 0;
+
+ obstack_ptr_grow (&search_obstack, base_binfo);
+ obstack_ptr_grow (&search_obstack, (HOST_WIDE_INT) depth);
+ obstack_ptr_grow (&search_obstack, (HOST_WIDE_INT) via_private);
+ tail += 3;
+ if (path_ptr)
+ {
+ obstack_ptr_grow (&search_obstack, basetype_path);
+ tail += 1;
+ }
+ if (tail >= search_stack->limit)
+ my_friendly_abort (93);
+ }
+#if 0
+ /* This code cannot possibly be right. Ambiguities can only be
+ checked by traversing the whole tree, and seeing if it pops
+ up twice. */
+ else if (! TREE_VIA_VIRTUAL (base_binfo))
+ {
+ rval = -2;
+ goto done;
+ }
+#endif
+ }
+
+ /* Process head of queue, if one exists. */
+ if (head >= tail)
+ break;
+
+ binfo = search_stack->first[head++];
+ depth = (int) search_stack->first[head++] + 1;
+ is_private = (int) search_stack->first[head++];
+ if (path_ptr)
+ {
+ basetype_path = search_stack->first[head++];
+ BINFO_INHERITANCE_CHAIN (binfo) = basetype_path;
+ basetype_path = binfo;
+ }
+ if (BINFO_TYPE (binfo) == parent)
+ {
+ /* It is wrong to set this and break, the proper thing to do
+ would be to set it only if it has not been set before,
+ and if is has been set, an ambiguity exists, and just
+ continue searching the tree for more of them as is done
+ in get_binfo. But until the code below can cope, this
+ can't be done. Also, it is not clear what should happen if
+ use_leftmost is set. */
+ rval = depth;
+ rval_private = is_private;
+ break;
+ }
+ }
+#if 0
+ /* Unneeded now, as we know the above code in the #if 0 is wrong. */
+ done:
+#endif
+ {
+ int increment = path_ptr ? 4 : 3;
+ tree *tp = search_stack->first;
+ tree *search_tail = tp + tail;
+
+ /* We can skip the first entry, since it wasn't marked. */
+ tp += increment;
+
+ basetype_path = binfo;
+ while (tp < search_tail)
+ {
+ CLEAR_BINFO_MARKED (*tp);
+ tp += increment;
+ }
+
+ /* Now, guarantee that we are following the leftmost path in the
+ chain. Algorithm: the search stack holds tuples in BFS order.
+ The last tuple on the search stack contains the tentative binfo
+ for the basetype we are looking for. We know that starting
+ with FIRST, each tuple with only a single basetype must be on
+ the leftmost path. Each time we come to a split, we select
+ the tuple for the leftmost basetype that can reach the ultimate
+ basetype. */
+
+ if (use_leftmost
+ && rval > 0
+ && (! BINFO_OFFSET_ZEROP (binfo) || TREE_VIA_VIRTUAL (binfo)))
+ {
+ tree tp_binfos;
+
+ /* Farm out the tuples with a single basetype. */
+ for (tp = search_stack->first; tp < search_tail; tp += increment)
+ {
+ tp_binfos = BINFO_BASETYPES (*tp);
+ if (tp_binfos && TREE_VEC_LENGTH (tp_binfos) > 1)
+ break;
+ }
+
+ if (tp < search_tail)
+ {
+ /* Pick the best path. */
+ tree base_binfo;
+ int i;
+ int nrval = rval;
+ for (i = 0; i < TREE_VEC_LENGTH (tp_binfos); i++)
+ {
+ base_binfo = TREE_VEC_ELT (tp_binfos, i);
+ if (tp+((i+1)*increment) < search_tail)
+ my_friendly_assert (base_binfo == tp[(i+1)*increment], 295);
+ if (nrval = recursive_bounded_basetype_p (binfo, base_binfo, rval, 1))
+ break;
+ }
+ rval = nrval;
+ if (rval > 0)
+ BINFO_INHERITANCE_CHAIN (base_binfo) = *tp;
+ }
+
+ /* Because I don't trust recursive_bounded_basetype_p to find
+ all ambiguities, I will just make sure here. When it is
+ sure that all ambiguities are found, the two routines and
+ this call can be removed. Not toally sure this should be
+ here, but I think it should. (mrs) */
+
+ if (get_binfo2 (parent, type) == error_mark_node && rval != -2)
+ {
+#if 1
+ /* This warning is here because the code over in
+ prepare_fresh_vtable relies on partial completion
+ offered by recursive_bounded_basetype_p I think, but
+ that behavior is not documented. It needs to be. I
+ don't think prepare_fresh_vtable is the only routine
+ that relies upon path_ptr being set to something in a
+ particular way when this routine returns -2. (mrs) */
+ /* See PR 428 for a test case that can tickle this. */
+ warning ("internal consistency check failed, please report, recovering.");
+ rval = -2;
+#endif
+ }
+
+ /* Visibilities don't count if we found an ambiguous basetype. */
+ if (rval == -2)
+ rval_private = 0;
+ }
+ }
+ search_stack = pop_search_level (search_stack);
+
+ if (rval && protect && rval_private)
+ return -3;
+
+ if (path_ptr)
+ *path_ptr = binfo;
+ return rval;
+}
+#endif
+
+/* Search for a member with name NAME in a multiple inheritance lattice
+ specified by TYPE. If it does not exist, return NULL_TREE.
+ If the member is ambiguously referenced, return `error_mark_node'.
+ Otherwise, return the FIELD_DECL. */
+
+/* Do a 1-level search for NAME as a member of TYPE. The caller
+ must figure out whether it has a visible path to 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);
+
+#ifdef GATHER_STATISTICS
+ n_calls_lookup_field_1++;
+#endif
+ while (field)
+ {
+#ifdef GATHER_STATISTICS
+ n_fields_searched++;
+#endif
+ if (DECL_NAME (field) == NULL_TREE
+ && TREE_CODE (TREE_TYPE (field)) == UNION_TYPE)
+ {
+ tree temp = lookup_field_1 (TREE_TYPE (field), name);
+ if (temp)
+ return temp;
+ }
+ if (DECL_NAME (field) == name)
+ {
+ if ((TREE_CODE(field) == VAR_DECL || TREE_CODE(field) == CONST_DECL)
+ && DECL_ASSEMBLER_NAME (field) != NULL)
+ GNU_xref_ref(current_function_decl,
+ IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (field)));
+ return field;
+ }
+ field = TREE_CHAIN (field);
+ }
+ /* Not found. */
+ if (name == _vptr_name)
+ {
+ /* Give the user what s/he thinks s/he wants. */
+ if (TYPE_VIRTUAL_P (type))
+ return CLASSTYPE_VFIELD (type);
+ }
+ return NULL_TREE;
+}
+
+/* Compute the visibility of FIELD. This is done by computing
+ the visibility available to each type in BASETYPES (which comes
+ as a list of [via_public/basetype] in reverse order, namely base
+ class before derived class). The first one which defines a
+ visibility defines the visibility for the field. Otherwise, the
+ visibility of the field is that which occurs normally.
+
+ Uses global variables CURRENT_CLASS_TYPE and
+ CURRENT_FUNCTION_DECL to use friend relationships
+ if necessary.
+
+ This will be static when lookup_fnfield comes into this file. */
+
+#define PUBLIC_RETURN return (DECL_PUBLIC (field) = 1), visibility_public
+#define PROTECTED_RETURN return (DECL_PROTECTED (field) = 1), visibility_protected
+#define PRIVATE_RETURN return (DECL_PRIVATE (field) = 1), visibility_private
+
+enum visibility_type
+compute_visibility (basetype_path, field)
+ tree basetype_path, field;
+{
+ enum visibility_type visibility = visibility_public;
+ tree types;
+ tree context = DECL_CLASS_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);
+
+ /* Virtual function tables are never private.
+ But we should know that we are looking for this,
+ and not even try to hide it. */
+ if (DECL_NAME (field) && VFIELD_NAME_P (DECL_NAME (field)) == 1)
+ return visibility_public;
+
+ /* Member function manipulating its own members. */
+ if (current_class_type == context
+ || (context && current_class_type == TYPE_MAIN_VARIANT (context)))
+ PUBLIC_RETURN;
+
+ /* Make these special cases fast. */
+ if (BINFO_TYPE (basetype_path) == current_class_type)
+ {
+ if (DECL_PUBLIC (field))
+ return visibility_public;
+ if (DECL_PROTECTED (field))
+ return visibility_protected;
+ if (DECL_PRIVATE (field))
+ return visibility_private;
+ }
+
+ /* Member found immediately within object. */
+ if (BINFO_INHERITANCE_CHAIN (basetype_path) == NULL_TREE)
+ {
+ /* At object's top level, public members are public. */
+ if (TREE_PROTECTED (field) == 0 && TREE_PRIVATE (field) == 0)
+ PUBLIC_RETURN;
+
+ /* Friend function manipulating members it gets (for being a friend). */
+ if (is_friend (context, current_function_decl))
+ PUBLIC_RETURN;
+
+ /* Inner than that, without special visibility,
+
+ protected members are ok if type of object is current_class_type
+ is derived therefrom. This means that if the type of the object
+ is a base type for our current class type, we cannot access
+ protected members.
+
+ private members are not ok. */
+ if (current_class_type && DECL_VISIBILITY (field) == NULL_TREE)
+ {
+ if (TREE_PRIVATE (field))
+ PRIVATE_RETURN;
+
+ if (TREE_PROTECTED (field))
+ {
+ if (context == current_class_type
+ || UNIQUELY_DERIVED_FROM_P (context, current_class_type))
+ PUBLIC_RETURN;
+ else
+ PROTECTED_RETURN;
+ }
+ else my_friendly_abort (94);
+ }
+ }
+ /* Friend function manipulating members it gets (for being a friend). */
+ if (is_friend (context, current_function_decl))
+ PUBLIC_RETURN;
+
+ /* must reverse more than one element */
+ basetype_path = reverse_path (basetype_path);
+ types = basetype_path;
+
+ while (types)
+ {
+ tree member;
+ tree binfo = types;
+ tree type = BINFO_TYPE (binfo);
+
+ member = purpose_member (type, DECL_VISIBILITY (field));
+ if (member)
+ {
+ visibility = (enum visibility_type)TREE_VALUE (member);
+ if (visibility == visibility_public
+ || is_friend (type, current_function_decl)
+ || (visibility == visibility_protected
+ && current_class_type
+ && UNIQUELY_DERIVED_FROM_P (context, current_class_type)))
+ visibility = visibility_public;
+ goto ret;
+ }
+
+ /* Friends inherit the visibility of the class they inherit from. */
+ if (is_friend (type, current_function_decl))
+ {
+ if (type == context)
+ {
+ visibility = visibility_public;
+ goto ret;
+ }
+ if (TREE_PROTECTED (field))
+ {
+ visibility = visibility_public;
+ goto ret;
+ }
+#if 0
+ /* This short-cut is too short. */
+ if (visibility == visibility_public)
+ goto ret;
+#endif
+ /* else, may be a friend of a deeper base class */
+ }
+
+ if (type == context)
+ break;
+
+ types = BINFO_INHERITANCE_CHAIN (types);
+ /* If the next type was not VIA_PUBLIC, then fields of all
+ remaining class past that one are private. */
+ if (types)
+ {
+ if (TREE_VIA_PROTECTED (types))
+ visibility = visibility_protected;
+ else if (! TREE_VIA_PUBLIC (types))
+ visibility = visibility_private;
+ }
+ }
+
+ /* No special visibilities apply. Use normal rules.
+ No assignment needed for BASETYPEs here from the nreverse.
+ This is because we use it only for information about the
+ path to the base. The code earlier dealt with what
+ happens when we are at the base level. */
+
+ if (visibility == visibility_public)
+ {
+ basetype_path = reverse_path (basetype_path);
+ if (TREE_PRIVATE (field))
+ PRIVATE_RETURN;
+ if (TREE_PROTECTED (field))
+ {
+ /* Used to check if the current class type was derived from
+ the type that contains the field. This is wrong for
+ multiple inheritance because is gives one class reference
+ to protected members via another classes protected path.
+ I.e., if A; B1 : A; B2 : A; Then B1 and B2 can access
+ their own members which are protected in A, but not
+ those same members in one another. */
+ if (current_class_type
+ && UNIQUELY_DERIVED_FROM_P (context, current_class_type))
+ PUBLIC_RETURN;
+ PROTECTED_RETURN;
+ }
+ PUBLIC_RETURN;
+ }
+
+ if (visibility == visibility_protected)
+ {
+ /* reverse_path? */
+ if (TREE_PRIVATE (field))
+ PRIVATE_RETURN;
+ /* We want to make sure that all non-private members in
+ the current class (as derived) are accessible. */
+ if (current_class_type
+ && UNIQUELY_DERIVED_FROM_P (context, current_class_type))
+ PUBLIC_RETURN;
+ PROTECTED_RETURN;
+ }
+
+ if (visibility == visibility_private
+ && current_class_type != NULL_TREE)
+ {
+ if (TREE_PRIVATE (field))
+ {
+ reverse_path (basetype_path);
+ PRIVATE_RETURN;
+ }
+
+ /* See if the field isn't protected. */
+ if (TREE_PROTECTED (field))
+ {
+ tree test = basetype_path;
+ while (test)
+ {
+ if (BINFO_TYPE (test) == current_class_type)
+ break;
+ test = BINFO_INHERITANCE_CHAIN (test);
+ }
+ reverse_path (basetype_path);
+ if (test)
+ PUBLIC_RETURN;
+ PROTECTED_RETURN;
+ }
+
+ /* See if the field isn't a public member of
+ a private base class. */
+
+ visibility = visibility_public;
+ types = BINFO_INHERITANCE_CHAIN (basetype_path);
+ while (types)
+ {
+ if (! TREE_VIA_PUBLIC (types))
+ {
+ if (visibility == visibility_private)
+ {
+ visibility = visibility_private;
+ goto ret;
+ }
+ visibility = visibility_private;
+ }
+ if (BINFO_TYPE (types) == context)
+ {
+ visibility = visibility_public;
+ goto ret;
+ }
+ types = BINFO_INHERITANCE_CHAIN (types);
+ }
+ my_friendly_abort (95);
+ }
+
+ ret:
+ reverse_path (basetype_path);
+
+ if (visibility == visibility_public)
+ DECL_PUBLIC (field) = 1;
+ else if (visibility == visibility_protected)
+ DECL_PROTECTED (field) = 1;
+ else if (visibility == visibility_private)
+ DECL_PRIVATE (field) = 1;
+ else my_friendly_abort (96);
+ return visibility;
+}
+
+/* Routine to see if the sub-object denoted by the binfo PARENT can be
+ 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;
+{
+ tree binfos = BINFO_BASETYPES (binfo);
+ int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+
+ if (parent == binfo)
+ return 1;
+
+ /* Process and/or queue base types. */
+ for (i = 0; i < n_baselinks; i++)
+ {
+ tree base_binfo = TREE_VEC_ELT (binfos, i);
+ if (TREE_VIA_VIRTUAL (base_binfo))
+ base_binfo = TYPE_BINFO (BINFO_TYPE (base_binfo));
+ if (is_subobject_of_p (parent, base_binfo))
+ return 1;
+ }
+ return 0;
+}
+
+/* See if a one FIELD_DECL hides another. This routine is meant to
+ 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. */
+static int
+hides (hider_binfo, hidee_binfo)
+ tree hider_binfo, hidee_binfo;
+{
+ /* hider hides hidee, if hider has hidee as a base class and
+ the instance of hidee is a sub-object of hider. The first
+ 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. */
+ 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);
+ tree fndecls;
+
+ if (index <= 0)
+ return index;
+ fndecls = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), index);
+ while (fndecls)
+ {
+ if (TYPE_MAIN_VARIANT (DECL_CLASS_CONTEXT (fndecls))
+ == TYPE_MAIN_VARIANT (type))
+ return index;
+ fndecls = TREE_CHAIN (fndecls);
+ }
+ return -1;
+}
+
+/* Look for a field named NAME in an inheritance lattice dominated by
+ XBASETYPE. PROTECT is zero if we can avoid computing visibility
+ 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.
+
+ 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;
+ enum visibility_type this_v = visibility_default;
+ tree entry, binfo, binfo_h;
+ enum visibility_type own_visibility = visibility_default;
+ int vbase_name_p = VBASE_NAME_P (name);
+
+ /* rval_binfo is the binfo associated with the found member, note,
+ this can be set with useful information, even when rval is not
+ set, because it must deal with ALL members, not just non-function
+ members. It is used for ambiguity checking and the hidden
+ checks. Whereas rval is only set if a proper (not hidden)
+ non-function member is found. */
+
+ /* 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
+ 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) */
+
+ /* Things for memoization. */
+ char *errstr = 0;
+
+ /* Set this to nonzero if we don't know how to compute
+ accurate error messages for visibility. */
+ int index = MEMOIZED_HASH_FN (name);
+
+ if (TREE_CODE (xbasetype) == TREE_VEC)
+ basetype_path = xbasetype, type = BINFO_TYPE (xbasetype);
+ else if (IS_AGGR_TYPE_CODE (TREE_CODE (xbasetype)))
+ basetype_path = TYPE_BINFO (xbasetype), type = xbasetype;
+ else my_friendly_abort (97);
+
+ if (CLASSTYPE_MTABLE_ENTRY (type))
+ {
+ tree tem = MEMOIZED_FIELDS (CLASSTYPE_MTABLE_ENTRY (type), index);
+
+ 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);
+ }
+ }
+
+#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;
+
+ rval = lookup_field_1 (type, name);
+ if (rval || lookup_fnfields_here (type, name)>=0)
+ {
+ rval_binfo = basetype_path;
+ rval_binfo_h = rval_binfo;
+ }
+
+ if (rval && TREE_CODE (rval) != TYPE_DECL && want_type)
+ rval = NULL_TREE;
+
+ if (rval)
+ {
+ if (protect)
+ {
+ if (TREE_PRIVATE (rval) | TREE_PROTECTED (rval))
+ this_v = compute_visibility (basetype_path, rval);
+ if (TREE_CODE (rval) == CONST_DECL)
+ {
+ if (this_v == visibility_private)
+ errstr = "enum `%s' is a private value of class `%s'";
+ else if (this_v == visibility_protected)
+ errstr = "enum `%s' is a protected value of class `%s'";
+ }
+ else
+ {
+ if (this_v == visibility_private)
+ errstr = "member `%s' is a private member of class `%s'";
+ else if (this_v == visibility_protected)
+ errstr = "member `%s' is a protected member of class `%s'";
+ }
+ }
+
+ 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)
+ {
+ error (errstr, IDENTIFIER_POINTER (name), TYPE_NAME_STRING (type));
+ return error_mark_node;
+ }
+ return rval;
+ }
+
+ basetype_chain = CLASSTYPE_BINFO_AS_LIST (type);
+ TREE_VIA_PUBLIC (basetype_chain) = 1;
+
+ /* The ambiguity check relies upon breadth first searching. */
+
+ search_stack = push_search_level (search_stack, &search_obstack);
+ BINFO_VIA_PUBLIC (basetype_path) = 1;
+ BINFO_INHERITANCE_CHAIN (basetype_path) = NULL_TREE;
+ binfo = basetype_path;
+ binfo_h = binfo;
+
+ while (1)
+ {
+ tree binfos = BINFO_BASETYPES (binfo);
+ int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+ tree nval;
+
+ /* Process and/or queue base types. */
+ for (i = 0; i < n_baselinks; i++)
+ {
+ tree base_binfo = TREE_VEC_ELT (binfos, i);
+ if (BINFO_FIELDS_MARKED (base_binfo) == 0)
+ {
+ tree btypes;
+
+ SET_BINFO_FIELDS_MARKED (base_binfo);
+ btypes = 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);
+ if (TREE_VIA_VIRTUAL (base_binfo))
+ btypes = tree_cons (NULL_TREE,
+ TYPE_BINFO (BINFO_TYPE (TREE_VEC_ELT (BINFO_BASETYPES (binfo_h), i))),
+ btypes);
+ else
+ btypes = tree_cons (NULL_TREE,
+ TREE_VEC_ELT (BINFO_BASETYPES (binfo_h), i),
+ btypes);
+ obstack_ptr_grow (&search_obstack, btypes);
+ tail += 1;
+ if (tail >= search_stack->limit)
+ my_friendly_abort (98);
+ }
+ }
+
+ /* Process head of queue, if one exists. */
+ if (head >= tail)
+ break;
+
+ basetype_chain = search_stack->first[head++];
+ binfo_h = TREE_VALUE (basetype_chain);
+ basetype_chain = TREE_CHAIN (basetype_chain);
+ basetype_path = TREE_VALUE (basetype_chain);
+ if (TREE_CHAIN (basetype_chain))
+ BINFO_INHERITANCE_CHAIN (basetype_path) = TREE_VALUE (TREE_CHAIN (basetype_chain));
+ else
+ BINFO_INHERITANCE_CHAIN (basetype_path) = NULL_TREE;
+
+ binfo = basetype_path;
+ type = BINFO_TYPE (binfo);
+
+ /* See if we can find NAME in TYPE. If RVAL is nonzero,
+ and we do find NAME in TYPE, verify that such a second
+ sighting is in fact legal. */
+
+ nval = lookup_field_1 (type, name);
+
+ if (nval || lookup_fnfields_here (type, name)>=0)
+ {
+ if (rval_binfo && hides (rval_binfo_h, binfo_h))
+ {
+ /* This is ok, the member found is in rval_binfo, not
+ here (binfo). */
+ }
+ else if (rval_binfo==NULL_TREE || hides (binfo_h, rval_binfo_h))
+ {
+ /* This is ok, the member found is here (binfo), not in
+ rval_binfo. */
+ if (nval)
+ {
+ rval = nval;
+ if (entry || protect)
+ this_v = compute_visibility (basetype_path, rval);
+ /* These may look ambiguous, but they really are not. */
+ if (vbase_name_p)
+ break;
+ }
+ else
+ {
+ /* Undo finding it before, as something else hides it. */
+ rval = NULL_TREE;
+ }
+ rval_binfo = binfo;
+ rval_binfo_h = binfo_h;
+ }
+ else
+ {
+ /* This is ambiguous. */
+ errstr = "request for member `%s' is ambiguous";
+ protect = 2;
+ break;
+ }
+ }
+ }
+ {
+ tree *tp = search_stack->first;
+ tree *search_tail = tp + tail;
+
+ if (entry)
+ TREE_VALUE (entry) = rval;
+
+ if (want_type && (rval == NULL_TREE || TREE_CODE (rval) != TYPE_DECL))
+ {
+ rval = NULL_TREE;
+ errstr = 0;
+ }
+
+ /* If this FIELD_DECL defines its own visibility, deal with that. */
+ if (rval && errstr == 0
+ && ((protect&1) || entry)
+ && DECL_LANG_SPECIFIC (rval)
+ && DECL_VISIBILITY (rval))
+ {
+ while (tp < search_tail)
+ {
+ /* If is possible for one of the derived types on the
+ path to have defined special visibility for this
+ field. Look for such declarations and report an
+ error if a conflict is found. */
+ enum visibility_type new_v;
+
+ if (this_v != visibility_default)
+ new_v = compute_visibility (TREE_VALUE (TREE_CHAIN (*tp)), rval);
+ if (this_v != visibility_default && new_v != this_v)
+ {
+ errstr = "conflicting visibilities to member `%s'";
+ this_v = visibility_default;
+ }
+ own_visibility = new_v;
+ CLEAR_BINFO_FIELDS_MARKED (TREE_VALUE (TREE_CHAIN (*tp)));
+ tp += 1;
+ }
+ }
+ else
+ {
+ while (tp < search_tail)
+ {
+ CLEAR_BINFO_FIELDS_MARKED (TREE_VALUE (TREE_CHAIN (*tp)));
+ tp += 1;
+ }
+ }
+ }
+ search_stack = pop_search_level (search_stack);
+
+ if (errstr == 0)
+ {
+ if (own_visibility == visibility_private)
+ errstr = "member `%s' declared private";
+ else if (own_visibility == visibility_protected)
+ errstr = "member `%s' declared protected";
+ else if (this_v == visibility_private)
+ errstr = TREE_PRIVATE (rval)
+ ? "member `%s' is private"
+ : "member `%s' is from private base class";
+ else if (this_v == visibility_protected)
+ errstr = TREE_PROTECTED (rval)
+ ? "member `%s' is protected"
+ : "member `%s' is from protected base class";
+ }
+
+ 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;
+ }
+ }
+
+ if (errstr && protect)
+ {
+ error (errstr, IDENTIFIER_POINTER (name), TYPE_NAME_STRING (type));
+ rval = error_mark_node;
+ }
+ return rval;
+}
+
+/* Try to find NAME inside a nested class. */
+tree
+lookup_nested_field (name, complain)
+ tree name;
+ int complain;
+{
+ register tree t;
+
+ tree id = NULL_TREE;
+ if (TREE_CHAIN (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);
+ t && DECL_CONTEXT (t);
+ t = TREE_CHAIN (DECL_CONTEXT (t)))
+ {
+ if (TREE_CODE (DECL_CONTEXT (t)) != RECORD_TYPE)
+ break;
+
+ /* N.B.: lookup_field will do the visibility checking for us */
+ id = lookup_field (DECL_CONTEXT (t), name, complain, 0);
+ if (id == error_mark_node)
+ {
+ id = NULL_TREE;
+ continue;
+ }
+
+ if (id != NULL_TREE)
+ {
+ if (TREE_CODE (id) == FIELD_DECL
+ && ! TREE_STATIC (id)
+ && TREE_TYPE (id) != error_mark_node)
+ {
+ if (complain)
+ {
+ /* At parse time, we don't want to give this error, since
+ we won't have enough state to make this kind of
+ decision properly. But there are times (e.g., with
+ enums in nested classes) when we do need to call
+ this fn at parse time. So, in those cases, we pass
+ complain as a 0 and just return a NULL_TREE. */
+ error ("assignment to non-static member `%s' of enclosing class `%s'",
+ lang_printable_name (id),
+ IDENTIFIER_POINTER (TYPE_IDENTIFIER
+ (DECL_CONTEXT (t))));
+ /* Mark this for do_identifier(). It would otherwise
+ claim that the variable was undeclared. */
+ TREE_TYPE (id) = error_mark_node;
+ }
+ else
+ {
+ id = NULL_TREE;
+ continue;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ return id;
+}
+
+/* TYPE is a class type. Return the index of the fields within
+ the method vector with name NAME, or -1 is no such field exists. */
+static int
+lookup_fnfields_1 (type, name)
+ tree type, name;
+{
+ register tree method_vec = CLASSTYPE_METHOD_VEC (type);
+
+ if (method_vec != 0)
+ {
+ register tree *methods = &TREE_VEC_ELT (method_vec, 0);
+ register tree *end = TREE_VEC_END (method_vec);
+
+#ifdef GATHER_STATISTICS
+ n_calls_lookup_fnfields_1++;
+#endif
+ if (*methods && name == constructor_name (type))
+ return 0;
+
+ while (++methods != end)
+ {
+#ifdef GATHER_STATISTICS
+ n_outer_fields_searched++;
+#endif
+ if (DECL_NAME (*methods) == name)
+ break;
+ }
+ if (methods != end)
+ return methods - &TREE_VEC_ELT (method_vec, 0);
+ }
+
+ return -1;
+}
+
+/* Starting from BASETYPE, return a TREE_BASELINK-like object
+ which gives the following information (in a list):
+
+ TREE_TYPE: list of basetypes needed to get to...
+ TREE_VALUE: list of all functions in of given type
+ which have name NAME.
+
+ No visibility information is computed by this function,
+ other then to adorn the list of basetypes with
+ TREE_VIA_PUBLIC.
+
+ If there are two ways to find a name (two members), if COMPLAIN is
+ non-zero, then error_mark_node is returned, and an error message is
+ printed, otherwise, just an error_mark_node is returned.
+
+ As a special case, is COMPLAIN is -1, we don't complain, and we
+ don't return error_mark_node, but rather the complete list of
+ virtuals. This is used by get_virtuals_named_this. */
+tree
+lookup_fnfields (basetype_path, name, complain)
+ tree basetype_path, name;
+ int complain;
+{
+ 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;
+
+ /* rval_binfo is the binfo associated with the found member, note,
+ this can be set with useful information, even when rval is not
+ set, because it must deal with ALL members, not just function
+ members. It is used for ambiguity checking and the hidden
+ checks. Whereas rval is only set if a proper (not hidden)
+ function member is found. */
+
+ /* rval_binfo_h and binfo_h are binfo values used when we perform the
+ hiding checks, as virtual base classes may not be shared. The strategy
+ is we always go into the the binfo hierarchy owned by TYPE_BINFO of
+ virtual base classes, as we cross virtual base class lines. This way
+ we know that binfo of a virtual base class will always == itself when
+ found along any line. (mrs) */
+
+ /* For now, don't try this. */
+ int protect = complain;
+
+ /* Things for memoization. */
+ char *errstr = 0;
+
+ /* Set this to nonzero if we don't know how to compute
+ accurate error messages for visibility. */
+ int index = MEMOIZED_HASH_FN (name);
+
+ if (complain == -1)
+ {
+ find_all = 1;
+ protect = complain = 0;
+ }
+
+ 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 visibility 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;
+ }
+ }
+ }
+
+#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;
+
+ index = lookup_fnfields_here (type, name);
+ if (index >= 0 || lookup_field_1 (type, name))
+ {
+ rval_binfo = basetype_path;
+ rval_binfo_h = rval_binfo;
+ }
+
+ if (index >= 0)
+ {
+ rval = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), index);
+ rvals = my_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;
+ }
+
+ if (errstr && protect)
+ {
+ error (errstr, IDENTIFIER_POINTER (name), TYPE_NAME_STRING (type));
+ return error_mark_node;
+ }
+ return rvals;
+ }
+ rval = NULL_TREE;
+
+ basetype_chain = CLASSTYPE_BINFO_AS_LIST (type);
+ TREE_VIA_PUBLIC (basetype_chain) = 1;
+
+ /* The ambiguity check relies upon breadth first searching. */
+
+ search_stack = push_search_level (search_stack, &search_obstack);
+ BINFO_VIA_PUBLIC (basetype_path) = 1;
+ BINFO_INHERITANCE_CHAIN (basetype_path) = NULL_TREE;
+ binfo = basetype_path;
+ binfo_h = binfo;
+
+ while (1)
+ {
+ tree binfos = BINFO_BASETYPES (binfo);
+ int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+ int index;
+
+ /* Process and/or queue base types. */
+ for (i = 0; i < n_baselinks; i++)
+ {
+ tree base_binfo = TREE_VEC_ELT (binfos, i);
+ if (BINFO_FIELDS_MARKED (base_binfo) == 0)
+ {
+ tree btypes;
+
+ SET_BINFO_FIELDS_MARKED (base_binfo);
+ btypes = 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);
+ if (TREE_VIA_VIRTUAL (base_binfo))
+ btypes = tree_cons (NULL_TREE,
+ TYPE_BINFO (BINFO_TYPE (TREE_VEC_ELT (BINFO_BASETYPES (binfo_h), i))),
+ btypes);
+ else
+ btypes = tree_cons (NULL_TREE,
+ TREE_VEC_ELT (BINFO_BASETYPES (binfo_h), i),
+ btypes);
+ obstack_ptr_grow (&search_obstack, btypes);
+ tail += 1;
+ if (tail >= search_stack->limit)
+ my_friendly_abort (99);
+ }
+ }
+
+ /* Process head of queue, if one exists. */
+ if (head >= tail)
+ break;
+
+ basetype_chain = search_stack->first[head++];
+ binfo_h = TREE_VALUE (basetype_chain);
+ basetype_chain = TREE_CHAIN (basetype_chain);
+ basetype_path = TREE_VALUE (basetype_chain);
+ if (TREE_CHAIN (basetype_chain))
+ BINFO_INHERITANCE_CHAIN (basetype_path) = TREE_VALUE (TREE_CHAIN (basetype_chain));
+ else
+ BINFO_INHERITANCE_CHAIN (basetype_path) = NULL_TREE;
+
+ binfo = basetype_path;
+ type = BINFO_TYPE (binfo);
+
+ /* See if we can find NAME in TYPE. If RVAL is nonzero,
+ and we do find NAME in TYPE, verify that such a second
+ sighting is in fact legal. */
+
+ index = lookup_fnfields_here (type, name);
+
+ if (index >= 0 || (lookup_field_1 (type, name)!=NULL_TREE && !find_all))
+ {
+ if (rval_binfo && !find_all && hides (rval_binfo_h, binfo_h))
+ {
+ /* This is ok, the member found is in rval_binfo, not
+ here (binfo). */
+ }
+ else if (rval_binfo==NULL_TREE || find_all || hides (binfo_h, rval_binfo_h))
+ {
+ /* This is ok, the member found is here (binfo), not in
+ rval_binfo. */
+ if (index >= 0)
+ {
+ rval = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), index);
+ /* Note, rvals can only be previously set if find_all is
+ true. */
+ rvals = my_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);
+ }
+ else
+ {
+ /* Undo finding it before, as something else hides it. */
+ rval = NULL_TREE;
+ rvals = NULL_TREE;
+ }
+ rval_binfo = binfo;
+ rval_binfo_h = binfo_h;
+ }
+ else
+ {
+ /* This is ambiguous. */
+ errstr = "request for member `%s' is ambiguous";
+ rvals = error_mark_node;
+ break;
+ }
+ }
+ }
+ {
+ tree *tp = search_stack->first;
+ tree *search_tail = tp + tail;
+
+ while (tp < search_tail)
+ {
+ CLEAR_BINFO_FIELDS_MARKED (TREE_VALUE (TREE_CHAIN (*tp)));
+ tp += 1;
+ }
+ }
+ search_stack = pop_search_level (search_stack);
+
+ if (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)
+ {
+ error (errstr, IDENTIFIER_POINTER (name), TYPE_NAME_STRING (type));
+ rvals = error_mark_node;
+ }
+
+ return rvals;
+}
+
+/* BREADTH-FIRST SEARCH ROUTINES. */
+
+/* Search a multiple inheritance hierarchy by breadth-first search.
+
+ TYPE 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
+breadth_first_search (binfo, testfn, qfn)
+ tree binfo;
+ int (*testfn)();
+ int (*qfn)();
+{
+ int head = 0, tail = 0;
+ int rval = 0;
+
+ search_stack = push_search_level (search_stack, &search_obstack);
+
+ while (1)
+ {
+ tree binfos = BINFO_BASETYPES (binfo);
+ int n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+ int i;
+
+ /* Process and/or queue base types. */
+ for (i = 0; i < n_baselinks; i++)
+ {
+ tree base_binfo = TREE_VEC_ELT (binfos, i);
+
+ if (BINFO_MARKED (base_binfo) == 0
+ && (qfn == 0 || (*qfn) (binfo, i)))
+ {
+ SET_BINFO_MARKED (base_binfo);
+ obstack_ptr_grow (&search_obstack, binfo);
+ obstack_ptr_grow (&search_obstack, (HOST_WIDE_INT) i);
+ tail += 2;
+ if (tail >= search_stack->limit)
+ my_friendly_abort (100);
+ }
+ }
+ /* Process head of queue, if one exists. */
+ if (head >= tail)
+ {
+ rval = 0;
+ break;
+ }
+
+ binfo = search_stack->first[head++];
+ i = (int) search_stack->first[head++];
+ if (rval = (*testfn) (binfo, i))
+ break;
+ binfo = BINFO_BASETYPE (binfo, i);
+ }
+ {
+ tree *tp = search_stack->first;
+ tree *search_tail = tp + tail;
+ while (tp < search_tail)
+ {
+ tree binfo = *tp++;
+ int i = (HOST_WIDE_INT)(*tp++);
+ CLEAR_BINFO_MARKED (BINFO_BASETYPE (binfo, i));
+ }
+ }
+
+ search_stack = pop_search_level (search_stack);
+ return rval;
+}
+
+/* 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_CONSTRUCTOR (basetype);
+}
+
+static tree declarator;
+
+static tree
+get_virtuals_named_this (binfo)
+ tree binfo;
+{
+ tree fields;
+
+ fields = lookup_fnfields (binfo, declarator, -1);
+ /* fields cannot be error_mark_node */
+
+ if (fields == 0)
+ return 0;
+
+ /* Get to the function decls, and return the first virtual function
+ with this name, if there is one. */
+ while (fields)
+ {
+ tree fndecl;
+
+ for (fndecl = TREE_VALUE (fields); fndecl; fndecl = DECL_CHAIN (fndecl))
+ if (DECL_VINDEX (fndecl))
+ return fields;
+ fields = next_baselink (fields);
+ }
+ return NULL_TREE;
+}
+
+static tree get_virtual_destructor (binfo, i)
+ 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);
+ return 0;
+}
+
+int tree_has_any_destructor_p (binfo, i)
+ 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);
+}
+
+/* Given a class type TYPE, and a function decl FNDECL,
+ look for the first function the TYPE's hierarchy which
+ FNDECL could match as a virtual function.
+
+ DTORP is nonzero if we are looking for a destructor. Destructors
+ need special treatment because they do not match by name. */
+tree
+get_first_matching_virtual (binfo, fndecl, dtorp)
+ tree binfo, fndecl;
+ int dtorp;
+{
+ tree tmp = 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)
+ {
+ if (get_base_distance (DECL_CONTEXT (tmp),
+ DECL_CONTEXT (fndecl), 0, 0) > 0)
+ DECL_CONTEXT (fndecl) = DECL_CONTEXT (tmp);
+ return tmp;
+ }
+
+ tmp = (tree) breadth_first_search (binfo,
+ (pfi) get_virtual_destructor,
+ tree_has_any_destructor_p);
+ if (tmp)
+ {
+ if (get_base_distance (DECL_CONTEXT (tmp),
+ DECL_CONTEXT (fndecl), 0, 0) > 0)
+ DECL_CONTEXT (fndecl) = DECL_CONTEXT (tmp);
+ }
+ return tmp;
+ }
+ else
+ {
+ tree drettype, dtypes, btypes, instptr_type;
+ tree basetype = DECL_CLASS_CONTEXT (fndecl);
+ tree baselink, best = NULL_TREE;
+ tree name = DECL_ASSEMBLER_NAME (fndecl);
+
+ declarator = DECL_NAME (fndecl);
+ if (IDENTIFIER_VIRTUAL_P (declarator) == 0)
+ return NULL_TREE;
+
+ drettype = TREE_TYPE (TREE_TYPE (fndecl));
+ dtypes = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
+ if (DECL_STATIC_FUNCTION_P (fndecl))
+ instptr_type = NULL_TREE;
+ else
+ instptr_type = TREE_TYPE (TREE_VALUE (dtypes));
+
+ for (baselink = get_virtuals_named_this (binfo);
+ baselink; baselink = next_baselink (baselink))
+ {
+ for (tmp = TREE_VALUE (baselink); tmp; tmp = DECL_CHAIN (tmp))
+ {
+ if (! DECL_VINDEX (tmp))
+ continue;
+
+ btypes = TYPE_ARG_TYPES (TREE_TYPE (tmp));
+ if (instptr_type == NULL_TREE)
+ {
+ if (compparms (TREE_CHAIN (btypes), dtypes, 3))
+ /* 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 (IDENTIFIER_ERROR_LOCUS (name) == NULL_TREE
+ && ! comptypes (TREE_TYPE (TREE_TYPE (tmp)), drettype, 1))
+ {
+ error_with_decl (fndecl, "conflicting return type specified for virtual function `%s'");
+ SET_IDENTIFIER_ERROR_LOCUS (name, basetype);
+ }
+ break;
+ }
+ }
+ if (tmp)
+ {
+ /* If this is ambiguous, we will warn about it later. */
+ if (best)
+ {
+ if (get_base_distance (DECL_CLASS_CONTEXT (best),
+ DECL_CLASS_CONTEXT (tmp), 0, 0) > 0)
+ best = tmp;
+ }
+ else
+ best = tmp;
+ }
+ }
+ if (IDENTIFIER_ERROR_LOCUS (name) == NULL_TREE
+ && best == NULL_TREE && warn_overloaded_virtual)
+ {
+ warning_with_decl (fndecl,
+ "conflicting specification deriving virtual function `%s'");
+ SET_IDENTIFIER_ERROR_LOCUS (name, basetype);
+ }
+ if (best)
+ {
+ if (get_base_distance (DECL_CONTEXT (best),
+ DECL_CONTEXT (fndecl), 0, 0) > 0)
+ DECL_CONTEXT (fndecl) = DECL_CONTEXT (best);
+ }
+ return best;
+ }
+}
+
+/* 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;
+{
+ /* For each layer of base class (i.e., the first base class, and each
+ virtual base class from that one), modify the virtual function table
+ of the derived class to contain the new virtual function.
+ A class has as many vfields as it has virtual base classes (total). */
+ tree vfields, vbases, base, tmp;
+ tree vfield = CLASSTYPE_VFIELD (type);
+ tree fcontext = vfield ? DECL_FCONTEXT (vfield) : NULL_TREE;
+ tree abstract_virtuals = CLASSTYPE_ABSTRACT_VIRTUALS (type);
+
+ for (vfields = CLASSTYPE_VFIELDS (type); vfields; vfields = TREE_CHAIN (vfields))
+ {
+ int normal;
+
+ /* This code is most likely wrong, and probably only works for single
+ inheritance or by accident. */
+
+ /* Find the right base class for this derived class, call it BASE. */
+ base = VF_BASETYPE_VALUE (vfields);
+ if (base == type)
+ continue;
+
+ /* We call this case NORMAL iff this virtual function table
+ pointer field has its storage reserved in this class.
+ This is normally the case without virtual baseclasses
+ or off-center multiple baseclasses. */
+ normal = (base == fcontext
+ && (VF_BINFO_VALUE (vfields) == NULL_TREE
+ || ! TREE_VIA_VIRTUAL (VF_BINFO_VALUE (vfields))));
+
+ if (normal)
+ tmp = TREE_CHAIN (TYPE_BINFO_VIRTUALS (type));
+ else
+ {
+ /* n.b.: VF_BASETYPE_VALUE (vfields) is the first basetype
+ that provides the virtual function table, whereas
+ VF_DERIVED_VALUE (vfields) is an immediate base type of TYPE
+ that dominates VF_BASETYPE_VALUE (vfields). The list of
+ vfields we want lies between these two values. */
+ tree binfo = get_binfo (VF_NORMAL_VALUE (vfields), type, 0);
+ tmp = TREE_CHAIN (BINFO_VIRTUALS (binfo));
+ }
+
+ /* Get around dossier entry if there is one. */
+ if (flag_dossier)
+ tmp = TREE_CHAIN (tmp);
+
+ while (tmp)
+ {
+ tree base_pfn = FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (tmp));
+ tree base_fndecl = TREE_OPERAND (base_pfn, 0);
+ if (DECL_ABSTRACT_VIRTUAL_P (base_fndecl))
+ abstract_virtuals = tree_cons (NULL_TREE, base_fndecl, abstract_virtuals);
+ tmp = TREE_CHAIN (tmp);
+ }
+ }
+ for (vbases = CLASSTYPE_VBASECLASSES (type); vbases; vbases = TREE_CHAIN (vbases))
+ {
+ if (! BINFO_VIRTUALS (vbases))
+ continue;
+
+ tmp = TREE_CHAIN (BINFO_VIRTUALS (vbases));
+ while (tmp)
+ {
+ tree base_pfn = FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (tmp));
+ tree base_fndecl = TREE_OPERAND (base_pfn, 0);
+ if (DECL_ABSTRACT_VIRTUAL_P (base_fndecl))
+ abstract_virtuals = tree_cons (NULL_TREE, base_fndecl, abstract_virtuals);
+ tmp = TREE_CHAIN (tmp);
+ }
+ }
+ return nreverse (abstract_virtuals);
+}
+
+/* For the type TYPE, return a list of member functions available from
+ base classes with name NAME. The TREE_VALUE of the list is a chain of
+ member functions with name NAME. The TREE_PURPOSE of the list is a
+ basetype, or a list of base types (in reverse order) which were
+ traversed to reach the chain of member functions. If we reach a base
+ type which provides a member function of name NAME, and which has at
+ most one base type itself, then we can terminate the search. */
+
+tree
+get_baselinks (type_as_binfo_list, type, name)
+ tree type_as_binfo_list;
+ tree type, name;
+{
+ int head = 0, tail = 0, index;
+ tree rval = 0, nval = 0;
+ tree basetypes = type_as_binfo_list;
+ tree binfo = TYPE_BINFO (type);
+
+ search_stack = push_search_level (search_stack, &search_obstack);
+
+ while (1)
+ {
+ tree binfos = BINFO_BASETYPES (binfo);
+ int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+
+ /* Process and/or queue base types. */
+ for (i = 0; i < n_baselinks; i++)
+ {
+ tree base_binfo = TREE_VEC_ELT (binfos, i);
+ tree btypes;
+
+ btypes = hash_tree_cons (TREE_VIA_PUBLIC (base_binfo),
+ TREE_VIA_VIRTUAL (base_binfo),
+ TREE_VIA_PROTECTED (base_binfo),
+ NULL_TREE, base_binfo,
+ basetypes);
+ obstack_ptr_grow (&search_obstack, btypes);
+ search_stack->first = (tree *)obstack_base (&search_obstack);
+ tail += 1;
+ }
+
+ dont_queue:
+ /* Process head of queue, if one exists. */
+ if (head >= tail)
+ break;
+
+ basetypes = search_stack->first[head++];
+ binfo = TREE_VALUE (basetypes);
+ type = BINFO_TYPE (binfo);
+ index = lookup_fnfields_1 (type, name);
+ if (index >= 0)
+ {
+ nval = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), index);
+ 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);
+ goto dont_queue;
+ }
+ }
+ nval = NULL_TREE;
+ }
+
+ search_stack = pop_search_level (search_stack);
+ return rval;
+}
+
+tree
+next_baselink (baselink)
+ tree baselink;
+{
+ tree tmp = TREE_TYPE (baselink);
+ baselink = TREE_CHAIN (baselink);
+ while (tmp)
+ {
+ /* @@ does not yet add previous base types. */
+ baselink = tree_cons (TREE_PURPOSE (tmp), TREE_VALUE (tmp),
+ baselink);
+ TREE_TYPE (baselink) = TREE_TYPE (tmp);
+ tmp = TREE_CHAIN (tmp);
+ }
+ return baselink;
+}
+
+/* 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. */
+static tree
+convert_pointer_to_single_level (to_type, expr)
+ tree to_type, expr;
+{
+ tree binfo_of_derived;
+ tree last;
+
+ 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, TYPE_POINTER_TO (to_type), expr, last, 1);
+}
+
+/* The main function which implements depth first search.
+
+ This routine has to remember the path it walked up, when
+ dfs_init_vbase_pointers is the work function, as otherwise there
+ would be no record. */
+static void
+dfs_walk (binfo, fn, qfn)
+ tree binfo;
+ void (*fn)();
+ int (*qfn)();
+{
+ 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);
+
+ if ((*qfn)(base_binfo))
+ {
+#define NEW_CONVERT 1
+#if NEW_CONVERT
+ if (fn == dfs_init_vbase_pointers)
+ {
+ /* When traversing an arbitrary MI hierarchy, we need to keep
+ a record of the path we took to get down to the final base
+ type, as otherwise there would be no record of it, and just
+ trying to blindly convert at the bottom would be ambiguous.
+
+ The easiest way is to do the conversions one step at a time,
+ as we know we want the immediate base class at each step.
+
+ The only special trick to converting one step at a time,
+ is that when we hit the last virtual base class, we must
+ use the SLOT value for it, and not use the normal convert
+ routine. We use the last virtual base class, as in our
+ implementation, we have pointers to all virtual base
+ classes in the base object. */
+
+ tree saved_vbase_decl_ptr_intermediate
+ = vbase_decl_ptr_intermediate;
+
+ if (TREE_VIA_VIRTUAL (base_binfo))
+ {
+ /* 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));
+ }
+ else
+ {
+#ifdef CHECK_convert_pointer_to_single_level
+ /* This code here introduces a little software fault
+ tolerance It should be that case that the second
+ one always gets the same valid answer that the
+ first one gives, if the first one gives a valid
+ answer.
+
+ If it doesn't, the second algorithm is at fault
+ and needs to be fixed.
+
+ The first one is known to be bad and produce
+ error_mark_node when dealing with MI base
+ classes. It is the only problem supposed to be
+ fixed by the second. */
+#endif
+ tree vdpi1, vdpi2;
+
+#ifdef CHECK_convert_pointer_to_single_level
+ vdpi1 = convert_pointer_to (BINFO_TYPE (base_binfo),
+ vbase_decl_ptr_intermediate);
+#endif
+ vdpi2 = convert_pointer_to_single_level (BINFO_TYPE (base_binfo),
+ vbase_decl_ptr_intermediate);
+ vbase_decl_ptr_intermediate = vdpi2;
+#ifdef CHECK_convert_pointer_to_single_level
+ if (vdpi1 == error_mark_node && vdpi2 != vdpi1)
+ {
+ extern int errorcount;
+ errorcount -=2;
+ warning ("internal: Don't worry, be happy, I can fix tangs man. (ignore above error)");
+ }
+ else if (simple_cst_equal (vdpi1, vdpi2) != 1) {
+ if (simple_cst_equal (vdpi1, vdpi2) == 0)
+ warning ("internal: convert_pointer_to_single_level: They are not the same, going with old algorithm");
+ else
+ warning ("internal: convert_pointer_to_single_level: They might not be the same, going with old algorithm");
+ vbase_decl_ptr_intermediate = vdpi1;
+ }
+#endif
+ }
+
+ dfs_walk (base_binfo, fn, qfn);
+
+ vbase_decl_ptr_intermediate = saved_vbase_decl_ptr_intermediate;
+ } else
+#endif
+ 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; }
+
+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; }
+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; }
+
+static int dfs_search_slot_nonempty_p (binfo) tree binfo;
+{ return CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (binfo)) != 0; }
+
+static int dfs_debug_unmarkedp (binfo) tree binfo;
+{ return CLASSTYPE_DEBUG_REQUESTED (BINFO_TYPE (binfo)) == 0; }
+
+/* The worker functions for `dfs_walk'. These do not need to
+ 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;
+}
+
+static void
+dfs_mark (binfo) tree binfo;
+{ SET_BINFO_MARKED (binfo); }
+
+static void
+dfs_unmark (binfo) tree binfo;
+{ CLEAR_BINFO_MARKED (binfo); }
+
+static void
+dfs_mark_vtable_path (binfo) tree binfo;
+{ SET_BINFO_VTABLE_PATH_MARKED (binfo); }
+
+static void
+dfs_unmark_vtable_path (binfo) tree binfo;
+{ CLEAR_BINFO_VTABLE_PATH_MARKED (binfo); }
+
+static void
+dfs_mark_new_vtable (binfo) tree binfo;
+{ SET_BINFO_NEW_VTABLE_MARKED (binfo); }
+
+static void
+dfs_unmark_new_vtable (binfo) tree binfo;
+{ CLEAR_BINFO_NEW_VTABLE_MARKED (binfo); }
+
+static void
+dfs_clear_search_slot (binfo) tree binfo;
+{ CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (binfo)) = 0; }
+
+static void
+dfs_debug_mark (binfo)
+ tree binfo;
+{
+ tree t = BINFO_TYPE (binfo);
+
+ /* Use heuristic that if there are virtual functions,
+ ignore until we see a non-inline virtual function. */
+ tree methods = CLASSTYPE_METHOD_VEC (t);
+
+ CLASSTYPE_DEBUG_REQUESTED (t) = 1;
+
+ /* If interface info is known, the value of (?@@?) is correct. */
+ if (methods == 0
+ || ! CLASSTYPE_INTERFACE_UNKNOWN (t)
+ || (write_virtuals == 2 && TYPE_VIRTUAL_P (t)))
+ return;
+
+ /* If debug info is requested from this context for this type, supply it.
+ If debug info is requested from another context for this type,
+ see if some third context can supply it. */
+ if (current_function_decl == NULL_TREE
+ || DECL_CLASS_CONTEXT (current_function_decl) != t)
+ {
+ if (TREE_VEC_ELT (methods, 0))
+ methods = TREE_VEC_ELT (methods, 0);
+ else
+ methods = TREE_VEC_ELT (methods, 1);
+ while (methods)
+ {
+ if (DECL_VINDEX (methods)
+ && DECL_SAVED_INSNS (methods) == 0
+ && DECL_PENDING_INLINE_INFO (methods) == 0
+ && DECL_ABSTRACT_VIRTUAL_P (methods) == 0)
+ {
+ /* Somebody, somewhere is going to have to define this
+ virtual function. When they do, they will provide
+ the debugging info. */
+ return;
+ }
+ methods = TREE_CHAIN (methods);
+ }
+ }
+ /* We cannot rely on some alien method to solve our problems,
+ so we must write out the debug info ourselves. */
+ DECL_IGNORED_P (TYPE_NAME (t)) = 0;
+ if (! TREE_ASM_WRITTEN (TYPE_NAME (t)))
+ rest_of_type_compilation (t, global_bindings_p ());
+}
+
+/* Attach to the type of the virtual base class, the pointer to the
+ virtual base class, given the global pointer vbase_decl_ptr. */
+static void
+dfs_find_vbases (binfo)
+ tree binfo;
+{
+ tree binfos = BINFO_BASETYPES (binfo);
+ int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0;
+
+ for (i = n_baselinks-1; i >= 0; i--)
+ {
+ tree base_binfo = TREE_VEC_ELT (binfos, i);
+
+ if (TREE_VIA_VIRTUAL (base_binfo)
+ && CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (base_binfo)) == 0)
+ {
+ tree vbase = BINFO_TYPE (base_binfo);
+ tree binfo = binfo_member (vbase, vbase_types);
+
+ CLASSTYPE_SEARCH_SLOT (vbase)
+ = (char *) build (PLUS_EXPR, TYPE_POINTER_TO (vbase),
+ vbase_decl_ptr, BINFO_OFFSET (binfo));
+ }
+ }
+ SET_BINFO_VTABLE_PATH_MARKED (binfo);
+ SET_BINFO_NEW_VTABLE_MARKED (binfo);
+}
+
+static void
+dfs_init_vbase_pointers (binfo)
+ tree binfo;
+{
+ tree type = BINFO_TYPE (binfo);
+ tree fields = TYPE_FIELDS (type);
+ tree path, this_vbase_ptr;
+ int distance;
+
+ CLEAR_BINFO_VTABLE_PATH_MARKED (binfo);
+
+ /* If there is a dossier, it is the first field, though perhaps from
+ the base class. Otherwise, the first fields are virtual base class
+ pointer fields. */
+ if (CLASSTYPE_DOSSIER (type) && VFIELD_NAME_P (DECL_NAME (fields)))
+ /* Get past vtable for the object. */
+ fields = TREE_CHAIN (fields);
+
+ if (fields == NULL_TREE
+ || DECL_NAME (fields) == NULL_TREE
+ || ! VBASE_NAME_P (DECL_NAME (fields)))
+ return;
+
+#if NEW_CONVERT
+ this_vbase_ptr = vbase_decl_ptr_intermediate;
+
+ if (TYPE_POINTER_TO (type) != TREE_TYPE (this_vbase_ptr))
+ my_friendly_abort (125);
+#endif
+
+#if NEW_CONVERT == 0
+ distance = get_base_distance (type, TREE_TYPE (vbase_decl), 0, &path);
+ if (distance == -2)
+ {
+ error ("inheritance lattice too complex below");
+ }
+ while (path)
+ {
+ if (TREE_VIA_VIRTUAL (path))
+ break;
+ distance -= 1;
+ path = BINFO_INHERITANCE_CHAIN (path);
+ }
+
+ if (distance > 0)
+ this_vbase_ptr = convert_pointer_to (type, (tree)CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (path)));
+ else
+ this_vbase_ptr = convert_pointer_to (type, vbase_decl_ptr);
+
+ /* This happens when it is ambiguous. */
+ if (this_vbase_ptr == error_mark_node)
+ return;
+#endif
+
+ while (fields && DECL_NAME (fields)
+ && VBASE_NAME_P (DECL_NAME (fields)))
+ {
+ tree ref = build (COMPONENT_REF, TREE_TYPE (fields),
+ build_indirect_ref (this_vbase_ptr, 0), fields);
+ tree init = (tree)CLASSTYPE_SEARCH_SLOT (TREE_TYPE (TREE_TYPE (fields)));
+ vbase_init_result = tree_cons (binfo_member (TREE_TYPE (TREE_TYPE (fields)),
+ vbase_types),
+ build_modify_expr (ref, NOP_EXPR, init),
+ vbase_init_result);
+ fields = TREE_CHAIN (fields);
+ }
+}
+
+/* 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 type = BINFO_TYPE (binfo);
+ CLASSTYPE_SEARCH_SLOT (type) = 0;
+ CLEAR_BINFO_VTABLE_PATH_MARKED (binfo);
+ CLEAR_BINFO_NEW_VTABLE_MARKED (binfo);
+}
+
+tree
+init_vbase_pointers (type, decl_ptr)
+ tree type;
+ tree decl_ptr;
+{
+ if (TYPE_USES_VIRTUAL_BASECLASSES (type))
+ {
+ int old_flag = flag_this_is_variable;
+ tree binfo = TYPE_BINFO (type);
+ flag_this_is_variable = -2;
+ vbase_types = CLASSTYPE_VBASECLASSES (type);
+ vbase_decl_ptr = decl_ptr;
+ vbase_decl = build_indirect_ref (decl_ptr, 0);
+ vbase_decl_ptr_intermediate = vbase_decl_ptr;
+ vbase_init_result = NULL_TREE;
+ dfs_walk (binfo, dfs_find_vbases, unmarked_vtable_pathp);
+ dfs_walk (binfo, dfs_init_vbase_pointers, marked_vtable_pathp);
+ dfs_walk (binfo, dfs_clear_vbase_slots, marked_new_vtablep);
+ flag_this_is_variable = old_flag;
+ return vbase_init_result;
+ }
+ return 0;
+}
+
+/* Build a COMPOUND_EXPR which when expanded will generate the code
+ needed to initialize all the virtual function table slots of all
+ the virtual baseclasses. FOR_TYPE is the type which determines the
+ virtual baseclasses to use; TYPE is the type of the object to which
+ the initialization applies. TRUE_EXP is the true object we are
+ initializing, and DECL_PTR is the pointer to the sub-object we
+ are initializing.
+
+ CTOR_P is non-zero if the caller of this function is a top-level
+ constructor. It is zero when called from a destructor. When
+ non-zero, we can use computed offsets to store the vtables. When
+ zero, we must store new vtables through virtual baseclass pointers. */
+
+tree
+build_vbase_vtables_init (main_binfo, binfo, true_exp, decl_ptr, ctor_p)
+ tree main_binfo, binfo;
+ tree true_exp, decl_ptr;
+ int ctor_p;
+{
+ tree for_type = BINFO_TYPE (main_binfo);
+ tree type = BINFO_TYPE (binfo);
+ if (TYPE_USES_VIRTUAL_BASECLASSES (type))
+ {
+ int old_flag = flag_this_is_variable;
+ tree vtable_init_result = NULL_TREE;
+ tree vbases = CLASSTYPE_VBASECLASSES (type);
+
+ vbase_types = CLASSTYPE_VBASECLASSES (for_type);
+ 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, 0);
+
+ if (ctor_p)
+ {
+ /* This is an object of type IN_TYPE, */
+ flag_this_is_variable = -2;
+ dfs_walk (main_binfo, dfs_find_vbases, unmarked_new_vtablep);
+ }
+
+ /* Initialized with vtables of type TYPE. */
+ while (vbases)
+ {
+ /* This time through, not every class's vtable
+ is going to be initialized. That is, we only initialize
+ the "last" vtable pointer. */
+
+ if (CLASSTYPE_VSIZE (BINFO_TYPE (vbases)))
+ {
+ tree addr;
+ tree vtbl = BINFO_VTABLE (vbases);
+ tree init = build_unary_op (ADDR_EXPR, vtbl, 0);
+ assemble_external (vtbl);
+ TREE_USED (vtbl) = 1;
+
+ if (ctor_p == 0)
+ addr = convert_pointer_to (vbases, vbase_decl_ptr);
+ else
+ addr = (tree)CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (vbases));
+
+ if (addr)
+ {
+ tree ref = build_vfield_ref (build_indirect_ref (addr, 0),
+ BINFO_TYPE (vbases));
+ init = convert_force (TREE_TYPE (ref), init);
+ vtable_init_result = tree_cons (NULL_TREE, build_modify_expr (ref, NOP_EXPR, init),
+ vtable_init_result);
+ }
+ }
+ vbases = TREE_CHAIN (vbases);
+ }
+
+ dfs_walk (binfo, dfs_clear_vbase_slots, marked_new_vtablep);
+
+ flag_this_is_variable = old_flag;
+ if (vtable_init_result)
+ return build_compound_expr (vtable_init_result);
+ }
+ return error_mark_node;
+}
+
+void
+clear_search_slots (type)
+ tree type;
+{
+ dfs_walk (TYPE_BINFO (type),
+ dfs_clear_search_slot, dfs_search_slot_nonempty_p);
+}
+
+static void
+dfs_get_vbase_types (binfo)
+ tree binfo;
+{
+ int i;
+ tree binfos = BINFO_BASETYPES (binfo);
+ tree type = BINFO_TYPE (binfo);
+ tree these_vbase_types = CLASSTYPE_VBASECLASSES (type);
+
+ if (these_vbase_types)
+ {
+ while (these_vbase_types)
+ {
+ tree this_type = BINFO_TYPE (these_vbase_types);
+
+ /* We really need to start from a fresh copy of this
+ virtual basetype! CLASSTYPE_MARKED2 is the shortcut
+ for BINFO_VBASE_MARKED. */
+ if (! CLASSTYPE_MARKED2 (this_type))
+ {
+ vbase_types = make_binfo (integer_zero_node,
+ this_type,
+ TYPE_BINFO_VTABLE (this_type),
+ TYPE_BINFO_VIRTUALS (this_type),
+ vbase_types);
+ TREE_VIA_VIRTUAL (vbase_types) = 1;
+ SET_CLASSTYPE_MARKED2 (this_type);
+ }
+ these_vbase_types = TREE_CHAIN (these_vbase_types);
+ }
+ }
+ else for (i = binfos ? TREE_VEC_LENGTH (binfos)-1 : -1; i >= 0; i--)
+ {
+ tree base_binfo = TREE_VEC_ELT (binfos, i);
+ if (TREE_VIA_VIRTUAL (base_binfo) && ! BINFO_VBASE_MARKED (base_binfo))
+ {
+ vbase_types = make_binfo (integer_zero_node, BINFO_TYPE (base_binfo),
+ BINFO_VTABLE (base_binfo),
+ BINFO_VIRTUALS (base_binfo), vbase_types);
+ TREE_VIA_VIRTUAL (vbase_types) = 1;
+ SET_BINFO_VBASE_MARKED (base_binfo);
+ }
+ }
+ SET_BINFO_MARKED (binfo);
+}
+
+/* Some virtual baseclasses might be virtual baseclasses for
+ other virtual baseclasses. We sort the virtual baseclasses
+ topologically: in the list returned, the first virtual base
+ classes have no virtual baseclasses themselves, and any entry
+ on the list has no dependency on virtual base classes later in the
+ list. */
+tree
+get_vbase_types (type)
+ tree type;
+{
+ tree ordered_vbase_types = NULL_TREE, prev, next;
+ tree vbases;
+
+ vbase_types = NULL_TREE;
+ dfs_walk (TYPE_BINFO (type), dfs_get_vbase_types, unmarkedp);
+ dfs_walk (TYPE_BINFO (type), dfs_unmark, markedp);
+
+ while (vbase_types)
+ {
+ /* Now sort these types. This is essentially a bubble merge. */
+
+ /* Farm out virtual baseclasses which have no marked ancestors. */
+ for (vbases = vbase_types, prev = NULL_TREE;
+ vbases; vbases = next)
+ {
+ next = TREE_CHAIN (vbases);
+ /* If VBASES does not have any vbases itself, or it's
+ topologically safe, it goes into the sorted list. */
+ if (! CLASSTYPE_VBASECLASSES (BINFO_TYPE (vbases))
+ || BINFO_VBASE_MARKED (vbases) == 0)
+ {
+ if (prev)
+ TREE_CHAIN (prev) = TREE_CHAIN (vbases);
+ else
+ vbase_types = TREE_CHAIN (vbases);
+ TREE_CHAIN (vbases) = NULL_TREE;
+ ordered_vbase_types = chainon (ordered_vbase_types, vbases);
+ CLEAR_BINFO_VBASE_MARKED (vbases);
+ }
+ else
+ prev = vbases;
+ }
+
+ /* Now unmark types all of whose ancestors are now on the
+ `ordered_vbase_types' list. */
+ for (vbases = vbase_types; vbases; vbases = TREE_CHAIN (vbases))
+ {
+ /* If all our virtual baseclasses are unmarked, ok. */
+ tree t = CLASSTYPE_VBASECLASSES (BINFO_TYPE (vbases));
+ while (t && (BINFO_VBASE_MARKED (t) == 0
+ || ! CLASSTYPE_VBASECLASSES (BINFO_TYPE (t))))
+ t = TREE_CHAIN (t);
+ if (t == NULL_TREE)
+ CLEAR_BINFO_VBASE_MARKED (vbases);
+ }
+ }
+
+ return ordered_vbase_types;
+}
+
+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 * mi_size);
+ 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
+}
+
+/* Local variables for detecting ambiguities of virtual functions
+ when two or more classes are joined at a multiple inheritance
+ seam. */
+typedef struct
+{
+ tree decl;
+ tree args;
+ tree ptr;
+} mi_ventry;
+static mi_ventry *mi_vmatrix;
+static int *mi_vmax;
+static int mi_vrows, mi_vcols;
+#define MI_VMATRIX(ROW,COL) ((mi_vmatrix + (ROW)*mi_vcols)[COL])
+
+/* Build a table of virtual functions for a multiple-inheritance
+ structure. Here, there are N base classes, and at most
+ M entries per class.
+
+ This function does nothing if N is 0 or 1. */
+void
+build_mi_virtuals (rows, cols)
+ int rows, cols;
+{
+ if (rows < 2 || cols == 0)
+ return;
+ mi_vrows = rows;
+ mi_vcols = cols;
+ mi_vmatrix = (mi_ventry *)xmalloc ((rows+1) * cols * sizeof (mi_ventry));
+ mi_vmax = (int *)xmalloc ((rows+1) * sizeof (int));
+
+ bzero (mi_vmax, rows * sizeof (int));
+
+ /* Row indices start at 1, so adjust this. */
+ mi_vmatrix -= cols;
+ mi_vmax -= 1;
+}
+
+/* Comparison function for ordering virtual function table entries. */
+static int
+rank_mi_virtuals (v1, v2)
+ mi_ventry *v1, *v2;
+{
+ tree p1, p2;
+ int i;
+
+ i = (long) (DECL_NAME (v1->decl)) - (long) (DECL_NAME (v2->decl));
+ if (i)
+ return i;
+ p1 = v1->args;
+ p2 = v2->args;
+
+ if (p1 == p2)
+ return 0;
+
+ while (p1 && p2)
+ {
+ i = ((long) (TREE_VALUE (p1)) - (long) (TREE_VALUE (p2)));
+ if (i)
+ return i;
+
+ if (TREE_CHAIN (p1))
+ {
+ if (! TREE_CHAIN (p2))
+ return 1;
+ p1 = TREE_CHAIN (p1);
+ p2 = TREE_CHAIN (p2);
+ }
+ else if (TREE_CHAIN (p2))
+ return -1;
+ else
+ {
+ /* When matches of argument lists occur, pick lowest
+ address to keep searching time to a minimum on
+ later passes--like hashing, only different.
+ *MUST BE STABLE*. */
+ if ((long) (v2->args) < (long) (v1->args))
+ v1->args = v2->args;
+ else
+ v2->args = v1->args;
+ return 0;
+ }
+ }
+ return 0;
+}
+
+/* Install the virtuals functions got from the initializer VIRTUALS to
+ the table at index ROW. */
+void
+add_mi_virtuals (row, virtuals)
+ int row;
+ tree virtuals;
+{
+ int col = 0;
+
+ if (mi_vmatrix == 0)
+ return;
+ while (virtuals)
+ {
+ tree decl = TREE_OPERAND (FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (virtuals)), 0);
+ MI_VMATRIX (row, col).decl = decl;
+ MI_VMATRIX (row, col).args = FUNCTION_ARG_CHAIN (decl);
+ MI_VMATRIX (row, col).ptr = TREE_VALUE (virtuals);
+ virtuals = TREE_CHAIN (virtuals);
+ col += 1;
+ }
+ mi_vmax[row] = col;
+
+ qsort (mi_vmatrix + row * mi_vcols,
+ col,
+ sizeof (mi_ventry),
+ rank_mi_virtuals);
+}
+
+/* If joining two types results in an ambiguity in the virtual
+ function table, report such here. */
+void
+report_ambiguous_mi_virtuals (rows, type)
+ int rows;
+ tree type;
+{
+ int *mi_vmin;
+ int row1, col1, row, col;
+
+ if (mi_vmatrix == 0)
+ return;
+
+ /* Now virtuals are all sorted, so we merge to find ambiguous cases. */
+ mi_vmin = (int *)alloca ((rows+1) * sizeof (int));
+ bzero (mi_vmin, rows * sizeof (int));
+
+ /* adjust. */
+ mi_vmin -= 1;
+
+ /* For each base class with virtual functions (and this includes views
+ of the virtual baseclasses from different base classes), see that
+ each virtual function in that base class has a unique meet.
+
+ When the column loop is finished, THIS_DECL is in fact the meet.
+ If that value does not appear in the virtual function table for
+ the row, install it. This happens when that virtual function comes
+ from a virtual baseclass, or a non-leftmost baseclass. */
+
+ for (row1 = 1; row1 < rows; row1++)
+ {
+ tree this_decl = 0;
+
+ for (col1 = mi_vmax[row1]-1; col1 >= mi_vmin[row1]; col1--)
+ {
+ tree these_args = MI_VMATRIX (row1, col1).args;
+ tree this_context;
+
+ this_decl = MI_VMATRIX (row1, col1).decl;
+ if (this_decl == 0)
+ continue;
+ this_context = TYPE_BINFO (DECL_CLASS_CONTEXT (this_decl));
+
+ if (this_context != TYPE_BINFO (type))
+ this_context = get_binfo (this_context, type, 0);
+
+ for (row = row1+1; row <= rows; row++)
+ for (col = mi_vmax[row]-1; col >= mi_vmin[row]; col--)
+ {
+ mi_ventry this_entry;
+
+ if (MI_VMATRIX (row, col).decl == 0)
+ continue;
+
+ this_entry.decl = this_decl;
+ this_entry.args = these_args;
+ this_entry.ptr = MI_VMATRIX (row1, col1).ptr;
+ if (rank_mi_virtuals (&this_entry, &MI_VMATRIX (row, col)) == 0)
+ {
+ /* They are equal. There are four possibilities:
+
+ (1) Derived class is defining this virtual function.
+ (2) Two paths to the same virtual function in the
+ same base class.
+ (3) A path to a virtual function declared in one base
+ class, and another path to a virtual function in a
+ base class of the base class.
+ (4) Two paths to the same virtual function in different
+ base classes.
+
+ The first three cases are ok (non-ambiguous). */
+
+ tree that_context, tmp;
+ int this_before_that;
+
+ if (type == BINFO_TYPE (this_context))
+ /* case 1. */
+ goto ok;
+ that_context = get_binfo (DECL_CLASS_CONTEXT (MI_VMATRIX (row, col).decl), type, 0);
+ if (that_context == this_context)
+ /* case 2. */
+ goto ok;
+ if (that_context != NULL_TREE)
+ {
+ tmp = get_binfo (that_context, this_context, 0);
+ this_before_that = (that_context != tmp);
+ if (this_before_that == 0)
+ /* case 3a. */
+ goto ok;
+ tmp = get_binfo (this_context, that_context, 0);
+ this_before_that = (this_context == tmp);
+ if (this_before_that != 0)
+ /* case 3b. */
+ goto ok;
+
+ /* case 4. */
+ /* These two are not hard errors, but could be
+ symptoms of bad code. The resultant code
+ the compiler generates needs to be checked.
+ (mrs) */
+#if 0
+ error_with_decl (MI_VMATRIX (row, col).decl, "ambiguous virtual function `%s'");
+ error_with_decl (this_decl, "ambiguating function `%s' (joined by type `%s')", IDENTIFIER_POINTER (current_class_name));
+#endif
+ }
+ ok:
+ MI_VMATRIX (row, col).decl = 0;
+
+ /* Let zeros propagate. */
+ if (col == mi_vmax[row]-1)
+ {
+ int i = col;
+ while (i >= mi_vmin[row]
+ && MI_VMATRIX (row, i).decl == 0)
+ i--;
+ mi_vmax[row] = i+1;
+ }
+ else if (col == mi_vmin[row])
+ {
+ int i = col;
+ while (i < mi_vmax[row]
+ && MI_VMATRIX (row, i).decl == 0)
+ i++;
+ mi_vmin[row] = i;
+ }
+ }
+ }
+ }
+ }
+ free (mi_vmatrix + mi_vcols);
+ mi_vmatrix = 0;
+ free (mi_vmax + 1);
+ mi_vmax = 0;
+}
+
+/* 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
+ that have abstract virtual functions. */
+
+void
+note_debug_info_needed (type)
+ tree type;
+{
+ dfs_walk (TYPE_BINFO (type), dfs_debug_mark, dfs_debug_unmarkedp);
+}
+
+/* Subroutines of push_class_decls (). */
+
+/* Add the instance variables which this class contributed to the
+ current class binding contour. When a redefinition occurs,
+ if the redefinition is strictly within a single inheritance path,
+ we just overwrite (in the case of a data field) or
+ cons (in the case of a member function) the old declaration with
+ the new. If the fields are not within a single inheritance path,
+ we must cons them in either case. */
+
+static void
+dfs_pushdecls (binfo)
+ tree binfo;
+{
+ tree type = BINFO_TYPE (binfo);
+ tree fields, *methods, *end;
+ tree method_vec;
+
+ for (fields = TYPE_FIELDS (type); fields; fields = TREE_CHAIN (fields))
+ {
+ /* Unmark so that if we are in a constructor, and then find that
+ this field was initialized by a base initializer,
+ we can emit an error message. */
+ if (TREE_CODE (fields) == FIELD_DECL)
+ TREE_USED (fields) = 0;
+
+ if (DECL_NAME (fields) == NULL_TREE
+ && TREE_CODE (TREE_TYPE (fields)) == UNION_TYPE)
+ {
+ dfs_pushdecls (TYPE_BINFO (TREE_TYPE (fields)));
+ continue;
+ }
+ if (TREE_CODE (fields) != TYPE_DECL)
+ {
+ DECL_PUBLIC (fields) = 0;
+ DECL_PROTECTED (fields) = 0;
+ DECL_PRIVATE (fields) = 0;
+ }
+
+ if (DECL_NAME (fields))
+ {
+ tree value = IDENTIFIER_CLASS_VALUE (DECL_NAME (fields));
+ if (value)
+ {
+ tree context;
+
+ /* Possible ambiguity. If its defining type(s)
+ is (are all) derived from us, no problem. */
+
+ if (TREE_CODE (value) != TREE_LIST)
+ {
+ context = DECL_CLASS_CONTEXT (value);
+
+ if (context && (context == type
+ || TYPE_DERIVES_FROM (context, type)))
+ value = fields;
+ else
+ value = tree_cons (NULL_TREE, fields,
+ build_tree_list (NULL_TREE, value));
+ }
+ else
+ {
+ /* All children may derive from us, in which case
+ there is no problem. Otherwise, we have to
+ keep lists around of what the ambiguities might be. */
+ tree values;
+ int problem = 0;
+
+ for (values = value; values; values = TREE_CHAIN (values))
+ {
+ tree sub_values = TREE_VALUE (values);
+
+ if (TREE_CODE (sub_values) == TREE_LIST)
+ {
+ for (; sub_values; sub_values = TREE_CHAIN (sub_values))
+ {
+ context = DECL_CLASS_CONTEXT (TREE_VALUE (sub_values));
+
+ if (! TYPE_DERIVES_FROM (context, type))
+ {
+ value = tree_cons (NULL_TREE, TREE_VALUE (values), value);
+ problem = 1;
+ break;
+ }
+ }
+ }
+ else
+ {
+ context = DECL_CLASS_CONTEXT (sub_values);
+
+ if (! TYPE_DERIVES_FROM (context, type))
+ {
+ value = tree_cons (NULL_TREE, values, value);
+ problem = 1;
+ break;
+ }
+ }
+ }
+ if (! problem) value = fields;
+ }
+
+ /* Mark this as a potentially ambiguous member. */
+ if (TREE_CODE (value) == TREE_LIST)
+ {
+ /* Leaving TREE_TYPE blank is intentional.
+ We cannot use `error_mark_node' (lookup_name)
+ or `unknown_type_node' (all member functions use this). */
+ TREE_NONLOCAL_FLAG (value) = 1;
+ }
+
+ IDENTIFIER_CLASS_VALUE (DECL_NAME (fields)) = value;
+ }
+ else IDENTIFIER_CLASS_VALUE (DECL_NAME (fields)) = fields;
+ }
+ }
+
+ method_vec = CLASSTYPE_METHOD_VEC (type);
+ if (method_vec != 0)
+ {
+ /* Farm out constructors and destructors. */
+ methods = &TREE_VEC_ELT (method_vec, 1);
+ end = TREE_VEC_END (method_vec);
+
+ /* This does not work for multiple inheritance yet. */
+ while (methods != end)
+ {
+ /* This will cause lookup_name to return a pointer
+ to the tree_list of possible methods of this name.
+ If the order is a problem, we can nreverse them. */
+ tree tmp;
+ tree old = IDENTIFIER_CLASS_VALUE (DECL_NAME (*methods));
+
+ if (old && TREE_CODE (old) == TREE_LIST)
+ tmp = tree_cons (DECL_NAME (*methods), *methods, old);
+ else
+ {
+ /* Only complain if we shadow something we can access. */
+ if (old && (DECL_CLASS_CONTEXT (old) == current_class_type
+ || ! TREE_PRIVATE (old)))
+ /* Should figure out visibility more accurately. */
+ warning ("shadowing member `%s' with member function",
+ IDENTIFIER_POINTER (DECL_NAME (*methods)));
+ tmp = build_tree_list (DECL_NAME (*methods), *methods);
+ }
+
+ TREE_TYPE (tmp) = unknown_type_node;
+#if 0
+ TREE_OVERLOADED (tmp) = DECL_OVERLOADED (*methods);
+#endif
+ TREE_NONLOCAL_FLAG (tmp) = 1;
+ IDENTIFIER_CLASS_VALUE (DECL_NAME (*methods)) = tmp;
+
+ tmp = *methods;
+ while (tmp != 0)
+ {
+ DECL_PUBLIC (tmp) = 0;
+ DECL_PROTECTED (tmp) = 0;
+ DECL_PRIVATE (tmp) = 0;
+ tmp = DECL_CHAIN (tmp);
+ }
+
+ methods++;
+ }
+ }
+ SET_BINFO_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);
+
+ if (method_vec != 0)
+ {
+ /* Farm out constructors and destructors. */
+ tree *methods = &TREE_VEC_ELT (method_vec, 1);
+ tree *end = TREE_VEC_END (method_vec);
+
+ for (; methods != end; methods++)
+ {
+ tree tmp = IDENTIFIER_CLASS_VALUE (DECL_NAME (*methods));
+
+ /* This was replaced in scope by somebody else. Just leave it
+ alone. */
+ if (TREE_CODE (tmp) != TREE_LIST)
+ continue;
+
+ if (TREE_CHAIN (tmp) == NULL_TREE
+ && TREE_VALUE (tmp)
+ && DECL_CHAIN (TREE_VALUE (tmp)) == NULL_TREE)
+ {
+ IDENTIFIER_CLASS_VALUE (DECL_NAME (*methods)) = TREE_VALUE (tmp);
+ }
+ }
+ }
+ CLEAR_BINFO_MARKED (binfo);
+}
+
+/* When entering the scope of a class, we cache all of the
+ fields that that class provides within its inheritance
+ lattice. Where ambiguities result, we mark them
+ 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;
+
+#if 0
+ tree tags = CLASSTYPE_TAGS (type);
+
+ while (tags)
+ {
+ tree code_type_node;
+ tree tag;
+
+ switch (TREE_CODE (TREE_VALUE (tags)))
+ {
+ case ENUMERAL_TYPE:
+ code_type_node = enum_type_node;
+ break;
+ case RECORD_TYPE:
+ code_type_node = record_type_node;
+ break;
+ case CLASS_TYPE:
+ code_type_node = class_type_node;
+ break;
+ case UNION_TYPE:
+ code_type_node = union_type_node;
+ break;
+ default:
+ my_friendly_abort (297);
+ }
+ tag = xref_tag (code_type_node, TREE_PURPOSE (tags),
+ TYPE_BINFO_BASETYPE (TREE_VALUE (tags), 0));
+#if 0 /* not yet, should get fixed properly later */
+ pushdecl (make_type_decl (TREE_PURPOSE (tags), TREE_VALUE (tags)));
+#else
+ pushdecl (build_decl (TYPE_DECL, TREE_PURPOSE (tags), TREE_VALUE (tags)));
+#endif
+ }
+#endif
+
+ current_obstack = &bridge_obstack;
+ search_stack = push_search_level (search_stack, &bridge_obstack);
+
+ id = TYPE_IDENTIFIER (type);
+ if (IDENTIFIER_TEMPLATE (id) != 0)
+ {
+#if 0
+ tree tmpl = IDENTIFIER_TEMPLATE (id);
+ push_template_decls (DECL_ARGUMENTS (TREE_PURPOSE (tmpl)),
+ TREE_VALUE (tmpl), 1);
+#endif
+ overload_template_name (id, 0);
+ }
+
+ /* Push class fields into CLASS_VALUE scope, and mark. */
+ dfs_walk (TYPE_BINFO (type), dfs_pushdecls, unmarkedp);
+
+ /* Compress fields which have only a single entry
+ by a given name, and unmark. */
+ dfs_walk (TYPE_BINFO (type), dfs_compress_decls, markedp);
+ current_obstack = ambient_obstack;
+}
+
+static void
+dfs_popdecls (binfo)
+ tree binfo;
+{
+ tree type = BINFO_TYPE (binfo);
+ tree fields = TYPE_FIELDS (type);
+ tree method_vec = CLASSTYPE_METHOD_VEC (type);
+
+ while (fields)
+ {
+ if (DECL_NAME (fields) == NULL_TREE
+ && TREE_CODE (TREE_TYPE (fields)) == UNION_TYPE)
+ {
+ dfs_popdecls (TYPE_BINFO (TREE_TYPE (fields)));
+ }
+ else if (DECL_NAME (fields))
+ IDENTIFIER_CLASS_VALUE (DECL_NAME (fields)) = NULL_TREE;
+ fields = TREE_CHAIN (fields);
+ }
+ if (method_vec != 0)
+ {
+ tree *methods = &TREE_VEC_ELT (method_vec, 0);
+ tree *end = TREE_VEC_END (method_vec);
+
+ /* Clear out ctors and dtors. */
+ if (*methods)
+ IDENTIFIER_CLASS_VALUE (TYPE_IDENTIFIER (type)) = NULL_TREE;
+
+ for (methods += 1; methods != end; methods++)
+ IDENTIFIER_CLASS_VALUE (DECL_NAME (*methods)) = NULL_TREE;
+ }
+
+ SET_BINFO_MARKED (binfo);
+}
+
+void
+pop_class_decls (type)
+ tree type;
+{
+ tree binfo = TYPE_BINFO (type);
+
+ /* Clear out the IDENTIFIER_CLASS_VALUE which this
+ class may have occupied, and mark. */
+ dfs_walk (binfo, dfs_popdecls, unmarkedp);
+
+ /* Unmark. */
+ dfs_walk (binfo, dfs_unmark, markedp);
+
+#if 0
+ tmpl = IDENTIFIER_TEMPLATE (TYPE_IDENTIFIER (type));
+ if (tmpl != 0)
+ pop_template_decls (DECL_ARGUMENTS (TREE_PURPOSE (tmpl)),
+ TREE_VALUE (tmpl), 1);
+#endif
+
+ search_stack = pop_search_level (search_stack);
+}
+
+/* Given a base type PARENT, and a derived type TYPE, build
+ a name which distinguishes exactly the PARENT member of TYPE's type.
+
+ FORMAT is a string which controls how sprintf formats the name
+ we have generated.
+
+ For example, given
+
+ class A; class B; class C : A, B;
+
+ it is possible to distinguish "A" from "C's A". And given
+
+ class L;
+ class A : L; class B : L; class C : A, B;
+
+ it is possible to distinguish "L" from "A's L", and also from
+ "C's L from A".
+
+ Make sure to use the DECL_ASSEMBLER_NAME of the TYPE_NAME of the
+ type, as template have DECL_NAMEs like: X<int>, whereas the
+ DECL_ASSEMBLER_NAME is set to be something the assembler can handle.
+ */
+tree
+build_type_pathname (format, parent, type)
+ char *format;
+ tree parent, type;
+{
+ extern struct obstack temporary_obstack;
+ char *first, *base, *name;
+ int i;
+ tree id;
+
+ parent = TYPE_MAIN_VARIANT (parent);
+
+ /* Remember where to cut the obstack to. */
+ first = obstack_base (&temporary_obstack);
+
+ /* Put on TYPE+PARENT. */
+ obstack_grow (&temporary_obstack,
+ TYPE_ASSEMBLER_NAME_STRING (type),
+ TYPE_ASSEMBLER_NAME_LENGTH (type));
+#ifdef JOINER
+ obstack_1grow (&temporary_obstack, JOINER);
+#else
+ obstack_1grow (&temporary_obstack, '_');
+#endif
+ obstack_grow0 (&temporary_obstack,
+ TYPE_ASSEMBLER_NAME_STRING (parent),
+ TYPE_ASSEMBLER_NAME_LENGTH (parent));
+ i = obstack_object_size (&temporary_obstack);
+ base = obstack_base (&temporary_obstack);
+ obstack_finish (&temporary_obstack);
+
+ /* Put on FORMAT+TYPE+PARENT. */
+ obstack_blank (&temporary_obstack, strlen (format) + i + 1);
+ name = obstack_base (&temporary_obstack);
+ sprintf (name, format, base);
+ id = get_identifier (name);
+ obstack_free (&temporary_obstack, first);
+
+ return id;
+}
+
+static int
+bfs_unmark_finished_struct (binfo, i)
+ tree binfo;
+ int i;
+{
+ if (i >= 0)
+ binfo = BINFO_BASETYPE (binfo, i);
+
+ if (BINFO_NEW_VTABLE_MARKED (binfo))
+ {
+ tree decl, context;
+
+ if (TREE_VIA_VIRTUAL (binfo))
+ binfo = binfo_member (BINFO_TYPE (binfo),
+ CLASSTYPE_VBASECLASSES (current_class_type));
+
+ decl = BINFO_VTABLE (binfo);
+ context = DECL_CONTEXT (decl);
+ DECL_CONTEXT (decl) = 0;
+ if (write_virtuals >= 0
+ && DECL_INITIAL (decl) != BINFO_VIRTUALS (binfo))
+ DECL_INITIAL (decl) = build_nt (CONSTRUCTOR, NULL_TREE,
+ BINFO_VIRTUALS (binfo));
+ finish_decl (decl, DECL_INITIAL (decl), NULL_TREE, 0);
+ DECL_CONTEXT (decl) = context;
+ }
+ CLEAR_BINFO_VTABLE_PATH_MARKED (binfo);
+ CLEAR_BINFO_NEW_VTABLE_MARKED (binfo);
+ return 0;
+}
+
+void
+unmark_finished_struct (type)
+ tree type;
+{
+ tree binfo = TYPE_BINFO (type);
+ bfs_unmark_finished_struct (binfo, -1);
+ breadth_first_search (binfo, bfs_unmark_finished_struct, bfs_marked_vtable_pathp);
+}
+
+void
+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
+ fprintf (stderr, "no search statistics\n");
+#endif
+}
+
+void
+init_search_processing ()
+{
+ gcc_obstack_init (&search_obstack);
+ gcc_obstack_init (&type_obstack);
+ gcc_obstack_init (&type_obstack_entries);
+ gcc_obstack_init (&bridge_obstack);
+
+ /* 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;
+ 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;
+}