diff options
Diffstat (limited to 'gnu/gcc2/cc1plus/cp-search.c')
| -rw-r--r-- | gnu/gcc2/cc1plus/cp-search.c | 4284 |
1 files changed, 0 insertions, 4284 deletions
diff --git a/gnu/gcc2/cc1plus/cp-search.c b/gnu/gcc2/cc1plus/cp-search.c deleted file mode 100644 index 9f3e0a5a1549..000000000000 --- a/gnu/gcc2/cc1plus/cp-search.c +++ /dev/null @@ -1,4284 +0,0 @@ -/* 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; -} |
