/* Breadth-first and depth-first routines for searching multiple-inheritance lattice for GNU C++. Copyright (C) 1987, 89, 92-96, 1997 Free Software Foundation, Inc. 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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* High-level class interface. */ #include "config.h" #include "system.h" #include "tree.h" #include "cp-tree.h" #include "obstack.h" #include "flags.h" #include "rtl.h" #include "output.h" #include "toplev.h" #define obstack_chunk_alloc xmalloc #define obstack_chunk_free free extern struct obstack *current_obstack; extern tree abort_fndecl; #include "stack.h" /* Obstack used for remembering decision points of breadth-first. */ static struct obstack search_obstack; /* Methods for pushing and popping objects to and from obstacks. */ struct stack_level * push_stack_level (obstack, tp, size) struct obstack *obstack; char *tp; /* Sony NewsOS 5.0 compiler doesn't like void * here. */ int size; { struct stack_level *stack; obstack_grow (obstack, tp, size); stack = (struct stack_level *) ((char*)obstack_next_free (obstack) - 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 get_abstract_virtuals_1 PROTO((tree, int, tree)); static tree get_vbase_1 PROTO((tree, tree, unsigned int *)); static tree convert_pointer_to_vbase PROTO((tree, tree)); static tree lookup_field_1 PROTO((tree, tree)); static tree convert_pointer_to_single_level PROTO((tree, tree)); static int lookup_fnfields_1 PROTO((tree, tree)); static int lookup_fnfields_here PROTO((tree, tree)); static int is_subobject_of_p PROTO((tree, tree)); static int hides PROTO((tree, tree)); static tree virtual_context PROTO((tree, tree, tree)); static tree get_template_base_recursive PROTO((tree, tree, tree, int)); static void dfs_walk PROTO((tree, void (*) (tree), int (*) (tree))); static void dfs_check_overlap PROTO((tree)); static int dfs_no_overlap_yet PROTO((tree)); static void envelope_add_decl PROTO((tree, tree, tree *)); static int get_base_distance_recursive PROTO((tree, int, int, int, int *, tree *, tree, int, int *, int, int)); static void expand_upcast_fixups PROTO((tree, tree, tree, tree, tree, tree, tree *)); static void fixup_virtual_upcast_offsets PROTO((tree, tree, int, int, tree, tree, tree, tree, tree *)); static int markedp PROTO((tree)); static int unmarkedp PROTO((tree)); static int marked_vtable_pathp PROTO((tree)); static int unmarked_vtable_pathp PROTO((tree)); static int marked_new_vtablep PROTO((tree)); static int unmarked_new_vtablep PROTO((tree)); static int dfs_debug_unmarkedp PROTO((tree)); static void dfs_debug_mark PROTO((tree)); static void dfs_find_vbases PROTO((tree)); static void dfs_clear_vbase_slots PROTO((tree)); static void dfs_unmark PROTO((tree)); static void dfs_init_vbase_pointers PROTO((tree)); static void dfs_get_vbase_types PROTO((tree)); static void dfs_pushdecls PROTO((tree)); static void dfs_compress_decls PROTO((tree)); static void dfs_unuse_fields PROTO((tree)); static tree add_conversions PROTO((tree)); static tree get_virtuals_named_this PROTO((tree)); static tree get_virtual_destructor PROTO((tree)); static int tree_has_any_destructor_p PROTO((tree)); static int covariant_return_p PROTO((tree, tree)); static struct search_level *push_search_level PROTO((struct stack_level *, struct obstack *)); static struct search_level *pop_search_level PROTO((struct stack_level *)); static tree breadth_first_search PROTO((tree, tree (*) (tree), int (*) (tree))); static tree vbase_types; static tree vbase_decl_ptr_intermediate, vbase_decl_ptr; static tree vbase_init_result; /* Allocate a level of searching. */ static struct search_level * push_search_level (stack, obstack) struct stack_level *stack; 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. */ static struct search_level * pop_search_level (obstack) struct stack_level *obstack; { register struct search_level *stack = pop_stack_level (obstack); return stack; } static tree _vptr_name; /* Variables for gathering statistics. */ #ifdef GATHER_STATISTICS static int n_fields_searched; static int n_calls_lookup_field, n_calls_lookup_field_1; static int n_calls_lookup_fnfields, n_calls_lookup_fnfields_1; static int n_calls_get_base_type; static int n_outer_fields_searched; static int n_contexts_saved; #endif /* GATHER_STATISTICS */ /* This list is used by push_class_decls to know what decls need to be pushed into class scope. */ static tree closed_envelopes = NULL_TREE; /* Get a virtual binfo that is found inside BINFO's hierarchy that is the same type as the type given in PARENT. To be optimal, we want the first one that is found by going through the least number of virtual bases. This uses a clever algorithm that updates *depth when we find the vbase, and cuts off other paths of search when they reach that depth. */ static tree get_vbase_1 (parent, binfo, depth) tree parent, binfo; unsigned int *depth; { tree binfos; int i, n_baselinks; tree rval = NULL_TREE; if (BINFO_TYPE (binfo) == parent && TREE_VIA_VIRTUAL (binfo)) { *depth = 0; return binfo; } *depth = *depth - 1; 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); tree nrval; if (*depth == 0) break; nrval = get_vbase_1 (parent, base_binfo, depth); if (nrval) rval = nrval; } *depth = *depth+1; return rval; } /* Return the shortest path to vbase PARENT within BINFO, ignoring access and ambiguity. */ tree get_vbase (parent, binfo) tree parent; tree binfo; { unsigned int d = (unsigned int)-1; return get_vbase_1 (parent, binfo, &d); } /* Convert EXPR to a virtual base class of type TYPE. We know that EXPR is a non-null POINTER_TYPE to RECORD_TYPE. We also know that the type of what expr points to has a virtual base of type TYPE. */ static tree convert_pointer_to_vbase (type, expr) tree type; tree expr; { tree vb = get_vbase (type, TYPE_BINFO (TREE_TYPE (TREE_TYPE (expr)))); return convert_pointer_to_real (vb, expr); } /* 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. If PROTECT is 1, then check if access to a public field of PARENT would be private. Also check for ambiguity. */ tree get_binfo (parent, binfo, protect) register tree parent, binfo; int protect; { tree type = NULL_TREE; int dist; tree rval = NULL_TREE; if (TREE_CODE (parent) == TREE_VEC) parent = BINFO_TYPE (parent); else if (! IS_AGGR_TYPE_CODE (TREE_CODE (parent))) my_friendly_abort (89); if (TREE_CODE (binfo) == TREE_VEC) type = BINFO_TYPE (binfo); else if (IS_AGGR_TYPE_CODE (TREE_CODE (binfo))) type = binfo; else my_friendly_abort (90); dist = get_base_distance (parent, binfo, protect, &rval); if (dist == -3) { cp_error ("fields of `%T' are inaccessible in `%T' due to private inheritance", parent, type); return error_mark_node; } else if (dist == -2 && protect) { cp_error ("type `%T' is ambiguous base class for type `%T'", parent, type); return error_mark_node; } return rval; } /* This is the newer depth first get_base_distance routine. */ static int get_base_distance_recursive (binfo, depth, is_private, rval, rval_private_ptr, new_binfo_ptr, parent, protect, via_virtual_ptr, via_virtual, current_scope_in_chain) tree binfo; int depth, is_private, rval; int *rval_private_ptr; tree *new_binfo_ptr, parent; int protect, *via_virtual_ptr, via_virtual; int current_scope_in_chain; { tree binfos; int i, n_baselinks; if (protect && !current_scope_in_chain && is_friend (BINFO_TYPE (binfo), current_scope ())) current_scope_in_chain = 1; if (BINFO_TYPE (binfo) == parent || binfo == parent) { int better = 0; if (rval == -1) /* This is the first time we've found parent. */ better = 1; else if (tree_int_cst_equal (BINFO_OFFSET (*new_binfo_ptr), BINFO_OFFSET (binfo)) && *via_virtual_ptr && via_virtual) { /* A new path to the same vbase. If this one has better access or is shorter, take it. */ if (protect) better = *rval_private_ptr - is_private; if (better == 0) better = rval - depth; } else { /* Ambiguous base class. */ rval = depth = -2; /* If we get an ambiguity between virtual and non-virtual base class, return the non-virtual in case we are ignoring ambiguity. */ better = *via_virtual_ptr - via_virtual; } if (better > 0) { rval = depth; *rval_private_ptr = is_private; *new_binfo_ptr = binfo; *via_virtual_ptr = via_virtual; } 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); int via_private = (protect && (is_private || (!TREE_VIA_PUBLIC (base_binfo) && !(TREE_VIA_PROTECTED (base_binfo) && current_scope_in_chain) && !is_friend (BINFO_TYPE (binfo), current_scope ())))); int this_virtual = via_virtual || TREE_VIA_VIRTUAL (base_binfo); rval = get_base_distance_recursive (base_binfo, depth, via_private, rval, rval_private_ptr, new_binfo_ptr, parent, protect, via_virtual_ptr, this_virtual, current_scope_in_chain); /* If we've found a non-virtual, ambiguous base class, we don't need to keep searching. */ if (rval == -2 && *via_virtual_ptr == 0) return rval; } return rval; } /* Return the number of levels between type PARENT and the type given in BINFO, following the leftmost path to PARENT not found along a virtual path, if there are no real PARENTs (all come from virtual base classes), then follow the shortest public path to PARENT. Return -1 if TYPE is not derived from PARENT. Return -2 if PARENT is an ambiguous base class of TYPE, and PROTECT is non-negative. 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_VIRTUAL and TREE_VIA_PUBLIC set. PARENT can also be a binfo, in which case that exact parent is found and no other. convert_pointer_to_real uses this functionality. If BINFO is a binfo, its BINFO_INHERITANCE_CHAIN will be left alone. */ int get_base_distance (parent, binfo, protect, path_ptr) register tree parent, binfo; int protect; tree *path_ptr; { int rval; int rval_private = 0; tree type = NULL_TREE; tree new_binfo = NULL_TREE; int via_virtual; int watch_access = protect; /* Should we be completing types here? */ if (TREE_CODE (parent) != TREE_VEC) parent = complete_type (TYPE_MAIN_VARIANT (parent)); else complete_type (TREE_TYPE (parent)); if (TREE_CODE (binfo) == TREE_VEC) type = BINFO_TYPE (binfo); else if (IS_AGGR_TYPE_CODE (TREE_CODE (binfo))) { type = complete_type (binfo); binfo = TYPE_BINFO (type); if (path_ptr) my_friendly_assert (BINFO_INHERITANCE_CHAIN (binfo) == NULL_TREE, 980827); } else my_friendly_abort (92); if (parent == type || parent == binfo) { /* 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 = binfo; return 0; } if (path_ptr) watch_access = 1; rval = get_base_distance_recursive (binfo, 0, 0, -1, &rval_private, &new_binfo, parent, watch_access, &via_virtual, 0, 0); /* Access restrictions don't count if we found an ambiguous basetype. */ if (rval == -2 && protect >= 0) rval_private = 0; if (rval && protect && rval_private) return -3; /* If they gave us the real vbase binfo, which isn't in the main binfo tree, deal with it. This happens when we are called from expand_upcast_fixups. */ if (rval == -1 && TREE_CODE (parent) == TREE_VEC && parent == binfo_member (BINFO_TYPE (parent), CLASSTYPE_VBASECLASSES (type))) { my_friendly_assert (BINFO_INHERITANCE_CHAIN (parent) == binfo, 980827); new_binfo = parent; rval = 1; } if (path_ptr) *path_ptr = new_binfo; return rval; } /* 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 can access this field. (Since it is only one level, this is reasonable.) */ static tree lookup_field_1 (type, name) tree type, name; { register tree field; if (TREE_CODE (type) == TEMPLATE_TYPE_PARM || TREE_CODE (type) == TEMPLATE_TEMPLATE_PARM) /* The TYPE_FIELDS of a TEMPLATE_TYPE_PARM are not fields at all; instead TYPE_FIELDS is the TEMPLATE_PARM_INDEX. (Miraculously, the code often worked even when we treated the index as a list of fields!) */ return NULL_TREE; field = TYPE_FIELDS (type); #ifdef GATHER_STATISTICS n_calls_lookup_field_1++; #endif /* GATHER_STATISTICS */ while (field) { #ifdef GATHER_STATISTICS n_fields_searched++; #endif /* GATHER_STATISTICS */ my_friendly_assert (TREE_CODE_CLASS (TREE_CODE (field)) == 'd', 0); if (DECL_NAME (field) == NULL_TREE && TREE_CODE (TREE_TYPE (field)) == UNION_TYPE) { 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; } /* There are a number of cases we need to be aware of here: current_class_type current_function_decl global NULL NULL fn-local NULL SET class-local SET NULL class->fn SET SET fn->class SET SET Those last two make life interesting. If we're in a function which is itself inside a class, we need decls to go into the fn's decls (our second case below). But if we're in a class and the class itself is inside a function, we need decls to go into the decls for the class. To achieve this last goal, we must see if, when both current_class_ptr and current_function_decl are set, the class was declared inside that function. If so, we know to put the decls into the class's scope. */ tree current_scope () { if (current_function_decl == NULL_TREE) return current_class_type; if (current_class_type == NULL_TREE) return current_function_decl; if (DECL_CLASS_CONTEXT (current_function_decl) == current_class_type) return current_function_decl; return current_class_type; } /* Compute the access of FIELD. This is done by computing the access available to each type in BASETYPES (which comes as a list of [via_public/basetype] in reverse order, namely base class before derived class). The first one which defines a access defines the access for the field. Otherwise, the access of the field is that which occurs normally. 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. access_public_node means that the field can be accessed by the current lexical scope. access_protected_node means that the field cannot be accessed by the current lexical scope because it is protected. access_private_node means that the field cannot be accessed by the current lexical scope because it is private. */ #if 0 #define PUBLIC_RETURN return (DECL_PUBLIC (field) = 1), access_public_node #define PROTECTED_RETURN return (DECL_PROTECTED (field) = 1), access_protected_node #define PRIVATE_RETURN return (DECL_PRIVATE (field) = 1), access_private_node #else #define PUBLIC_RETURN return access_public_node #define PROTECTED_RETURN return access_protected_node #define PRIVATE_RETURN return access_private_node #endif #if 0 /* Disabled with DECL_PUBLIC &c. */ static tree previous_scope = NULL_TREE; #endif tree compute_access (basetype_path, field) tree basetype_path, field; { tree access; tree types; tree context; int protected_ok, via_protected; extern int flag_access_control; #if 1 /* Replaces static decl above. */ tree previous_scope; #endif int static_mem = ((TREE_CODE (field) == FUNCTION_DECL && DECL_STATIC_FUNCTION_P (field)) || (TREE_CODE (field) != FUNCTION_DECL && TREE_STATIC (field))); if (! flag_access_control) return access_public_node; /* The field lives in the current class. */ if (BINFO_TYPE (basetype_path) == current_class_type) return access_public_node; #if 0 /* Disabled until pushing function scope clears these out. If ever. */ /* Make these special cases fast. */ if (current_scope () == previous_scope) { if (DECL_PUBLIC (field)) return access_public_node; if (DECL_PROTECTED (field)) return access_protected_node; if (DECL_PRIVATE (field)) return access_private_node; } #endif /* We don't currently support access control on nested types. */ if (TREE_CODE (field) == TYPE_DECL) return access_public_node; previous_scope = current_scope (); context = DECL_REAL_CONTEXT (field); /* Fields coming from nested anonymous unions have their DECL_CLASS_CONTEXT slot set to the union type rather than the record type containing the anonymous union. */ if (context && ANON_UNION_TYPE_P (context) && TREE_CODE (field) == FIELD_DECL) context = TYPE_CONTEXT (context); /* Virtual function tables are never private. But we should know that we are looking for this, and not even try to hide it. */ if (DECL_NAME (field) && VFIELD_NAME_P (DECL_NAME (field)) == 1) PUBLIC_RETURN; /* Member found immediately within object. */ if (BINFO_INHERITANCE_CHAIN (basetype_path) == NULL_TREE) { /* Are we (or an enclosing scope) friends with the class that has FIELD? */ if (is_friend (context, previous_scope)) PUBLIC_RETURN; /* If it's private, it's private, you letch. */ if (TREE_PRIVATE (field)) PRIVATE_RETURN; /* ARM $11.5. Member functions of a derived class can access the non-static protected members of a base class only through a pointer to the derived class, a reference to it, or an object of it. Also any subsequently derived classes also have access. */ else if (TREE_PROTECTED (field)) { if (current_class_type && (static_mem || DECL_CONSTRUCTOR_P (field)) && ACCESSIBLY_DERIVED_FROM_P (context, current_class_type)) PUBLIC_RETURN; else PROTECTED_RETURN; } else PUBLIC_RETURN; } /* must reverse more than one element */ basetype_path = reverse_path (basetype_path); types = basetype_path; via_protected = 0; access = access_default_node; protected_ok = static_mem && current_class_type && ACCESSIBLY_DERIVED_FROM_P (BINFO_TYPE (types), current_class_type); while (1) { tree member; tree binfo = types; tree type = BINFO_TYPE (binfo); int private_ok = 0; /* Friends of a class can see protected members of its bases. Note that classes are their own friends. */ if (is_friend (type, previous_scope)) { protected_ok = 1; private_ok = 1; } member = purpose_member (type, DECL_ACCESS (field)); if (member) { access = TREE_VALUE (member); break; } types = BINFO_INHERITANCE_CHAIN (types); /* If the next type was VIA_PROTECTED, then fields of all remaining classes past that one are *at least* protected. */ if (types) { if (TREE_VIA_PROTECTED (types)) via_protected = 1; else if (! TREE_VIA_PUBLIC (types) && ! private_ok) { access = access_private_node; break; } } else break; } /* No special visibilities apply. Use normal rules. */ if (access == access_default_node) { if (is_friend (context, previous_scope)) access = access_public_node; else if (TREE_PRIVATE (field)) access = access_private_node; else if (TREE_PROTECTED (field)) access = access_protected_node; else access = access_public_node; } if (access == access_public_node && via_protected) access = access_protected_node; if (access == access_protected_node && protected_ok) access = access_public_node; #if 0 if (access == access_public_node) DECL_PUBLIC (field) = 1; else if (access == access_protected_node) DECL_PROTECTED (field) = 1; else if (access == access_private_node) DECL_PRIVATE (field) = 1; else my_friendly_abort (96); #endif return access; } /* 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 idx = lookup_fnfields_1 (type, name); tree fndecls; /* ctors and dtors are always only in the right class. */ if (idx <= 1) return idx; fndecls = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), idx); while (fndecls) { if (TYPE_MAIN_VARIANT (DECL_CLASS_CONTEXT (OVL_CURRENT (fndecls))) == TYPE_MAIN_VARIANT (type)) return idx; fndecls = OVL_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 access information, otherwise it is 1. WANT_TYPE is 1 when we should only return TYPE_DECLs, if no TYPE_DECL can be found return NULL_TREE. 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 = NULL_TREE; tree type = NULL_TREE, basetype_chain, basetype_path = NULL_TREE; tree this_v = access_default_node; tree entry, binfo, binfo_h; tree own_access = access_default_node; int vbase_name_p = VBASE_NAME_P (name); /* rval_binfo is the binfo associated with the found member, note, this can be set with useful information, even when rval is not set, because it must deal with ALL members, not just non-function members. It is used for ambiguity checking and the hidden checks. Whereas rval is only set if a proper (not hidden) non-function member is found. */ /* rval_binfo_h and binfo_h are binfo values used when we perform the hiding checks, as virtual base classes may not be shared. The strategy is we always go into the binfo hierarchy owned by TYPE_BINFO of virtual base classes, as we cross virtual base class lines. This way we know that binfo of a virtual base class will always == itself when found along any line. (mrs) */ char *errstr = 0; #if 0 /* We cannot search for constructor/destructor names like this. */ /* This can't go here, but where should it go? */ /* If we are looking for a constructor in a templated type, use the unspecialized name, as that is how we store it. */ if (IDENTIFIER_TEMPLATE (name)) name = constructor_name (name); #endif if (xbasetype == current_class_type && TYPE_BEING_DEFINED (xbasetype) && IDENTIFIER_CLASS_VALUE (name)) { tree field = IDENTIFIER_CLASS_VALUE (name); if (TREE_CODE (field) != FUNCTION_DECL && ! (want_type && TREE_CODE (field) != TYPE_DECL)) return field; } if (TREE_CODE (xbasetype) == TREE_VEC) { type = BINFO_TYPE (xbasetype); basetype_path = xbasetype; } else if (IS_AGGR_TYPE_CODE (TREE_CODE (xbasetype))) { type = xbasetype; basetype_path = TYPE_BINFO (type); my_friendly_assert (BINFO_INHERITANCE_CHAIN (basetype_path) == NULL_TREE, 980827); } else my_friendly_abort (97); complete_type (type); #ifdef GATHER_STATISTICS n_calls_lookup_field++; #endif /* GATHER_STATISTICS */ rval = lookup_field_1 (type, name); if (rval || lookup_fnfields_here (type, name) >= 0) { if (rval) { if (want_type) { if (TREE_CODE (rval) != TYPE_DECL) { rval = purpose_member (name, CLASSTYPE_TAGS (type)); if (rval) rval = TYPE_MAIN_DECL (TREE_VALUE (rval)); } } else { if (TREE_CODE (rval) == TYPE_DECL && lookup_fnfields_here (type, name) >= 0) rval = NULL_TREE; } } if (protect && rval) { if (TREE_PRIVATE (rval) | TREE_PROTECTED (rval)) this_v = compute_access (basetype_path, rval); if (TREE_CODE (rval) == CONST_DECL) { if (this_v == access_private_node) errstr = "enum `%D' is a private value of class `%T'"; else if (this_v == access_protected_node) errstr = "enum `%D' is a protected value of class `%T'"; } else { if (this_v == access_private_node) errstr = "member `%D' is a private member of class `%T'"; else if (this_v == access_protected_node) errstr = "member `%D' is a protected member of class `%T'"; } } rval_binfo = basetype_path; goto out; } basetype_chain = build_expr_list (NULL_TREE, basetype_path); /* The ambiguity check relies upon breadth first searching. */ search_stack = push_search_level (search_stack, &search_obstack); binfo = basetype_path; binfo_h = binfo; while (1) { tree binfos = BINFO_BASETYPES (binfo); int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0; tree nval; /* Process and/or queue base types. */ for (i = 0; i < n_baselinks; i++) { tree base_binfo = TREE_VEC_ELT (binfos, i); if (BINFO_FIELDS_MARKED (base_binfo) == 0) { tree btypes; SET_BINFO_FIELDS_MARKED (base_binfo); btypes = scratch_tree_cons (NULL_TREE, base_binfo, basetype_chain); if (TREE_VIA_VIRTUAL (base_binfo)) btypes = scratch_tree_cons (NULL_TREE, TYPE_BINFO (BINFO_TYPE (TREE_VEC_ELT (BINFO_BASETYPES (binfo_h), i))), btypes); else btypes = scratch_tree_cons (NULL_TREE, TREE_VEC_ELT (BINFO_BASETYPES (binfo_h), i), btypes); obstack_ptr_grow (&search_obstack, btypes); tail += 1; if (tail >= search_stack->limit) my_friendly_abort (98); } } /* Process head of queue, if one exists. */ if (head >= tail) break; basetype_chain = search_stack->first[head++]; binfo_h = TREE_VALUE (basetype_chain); basetype_chain = TREE_CHAIN (basetype_chain); basetype_path = TREE_VALUE (basetype_chain); if (TREE_CHAIN (basetype_chain)) my_friendly_assert ((BINFO_INHERITANCE_CHAIN (basetype_path) == TREE_VALUE (TREE_CHAIN (basetype_chain))) /* We only approximate base info for partial instantiations. */ || current_template_parms, 980827); else my_friendly_assert (BINFO_INHERITANCE_CHAIN (basetype_path) == NULL_TREE, 980827); 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 valid. */ nval = lookup_field_1 (type, name); if (nval || lookup_fnfields_here (type, name)>=0) { if (nval && nval == rval && SHARED_MEMBER_P (nval)) { /* This is ok, the member found is the same [class.ambig] */ } else if (rval_binfo && hides (rval_binfo_h, binfo_h)) { /* This is ok, the member found is in rval_binfo, not here (binfo). */ } else if (rval_binfo==NULL_TREE || hides (binfo_h, rval_binfo_h)) { /* This is ok, the member found is here (binfo), not in rval_binfo. */ if (nval) { rval = nval; if (protect) this_v = compute_access (basetype_path, rval); /* These may look ambiguous, but they really are not. */ if (vbase_name_p) break; } else { /* Undo finding it before, as something else hides it. */ rval = NULL_TREE; } rval_binfo = binfo; rval_binfo_h = binfo_h; } else { /* This is ambiguous. */ errstr = "request for member `%D' is ambiguous"; protect += 2; break; } } } { tree *tp = search_stack->first; tree *search_tail = tp + tail; if (rval_binfo) { type = BINFO_TYPE (rval_binfo); if (rval) { if (want_type) { if (TREE_CODE (rval) != TYPE_DECL) { rval = purpose_member (name, CLASSTYPE_TAGS (type)); if (rval) rval = TYPE_MAIN_DECL (TREE_VALUE (rval)); } } else { if (TREE_CODE (rval) == TYPE_DECL && lookup_fnfields_here (type, name) >= 0) rval = NULL_TREE; } } } if (rval == NULL_TREE) errstr = 0; /* If this FIELD_DECL defines its own access level, deal with that. */ if (rval && errstr == 0 && (protect & 1) && DECL_LANG_SPECIFIC (rval) && DECL_ACCESS (rval)) { while (tp < search_tail) { /* If is possible for one of the derived types on the path to have defined special access for this field. Look for such declarations and report an error if a conflict is found. */ tree new_v = NULL_TREE; if (this_v != access_default_node) new_v = compute_access (TREE_VALUE (TREE_CHAIN (*tp)), rval); if (this_v != access_default_node && new_v != this_v) { errstr = "conflicting access to member `%D'"; this_v = access_default_node; } own_access = new_v; CLEAR_BINFO_FIELDS_MARKED (TREE_VALUE (TREE_CHAIN (*tp))); tp += 1; } } else { while (tp < search_tail) { CLEAR_BINFO_FIELDS_MARKED (TREE_VALUE (TREE_CHAIN (*tp))); tp += 1; } } } search_stack = pop_search_level (search_stack); if (errstr == 0) { if (own_access == access_private_node) errstr = "member `%D' declared private"; else if (own_access == access_protected_node) errstr = "member `%D' declared protected"; else if (this_v == access_private_node) errstr = TREE_PRIVATE (rval) ? "member `%D' is private" : "member `%D' is from private base class"; else if (this_v == access_protected_node) errstr = TREE_PROTECTED (rval) ? "member `%D' is protected" : "member `%D' is from protected base class"; } out: if (protect == 2) { /* If we are not interested in ambiguities, don't report them, just return NULL_TREE. */ rval = NULL_TREE; protect = 0; } if (errstr && protect) { cp_error (errstr, name, type); rval = error_mark_node; } /* Do implicit typename stuff. This code also handles out-of-class definitions of nested classes whose enclosing class is a template. For example: template struct S { struct I { void f(); }; }; template void S::I::f() {} will come through here to handle `S::I'. */ if (rval && processing_template_decl && ! currently_open_class (BINFO_TYPE (rval_binfo)) && uses_template_parms (type)) { /* Don't return a non-type. Actually, we ought to return something so lookup_name_real can give a warning. */ if (TREE_CODE (rval) != TYPE_DECL) return NULL_TREE; binfo = rval_binfo; for (; ; binfo = BINFO_INHERITANCE_CHAIN (binfo)) if (BINFO_INHERITANCE_CHAIN (binfo) == NULL_TREE || (BINFO_TYPE (BINFO_INHERITANCE_CHAIN (binfo)) == current_class_type)) break; entry = build_typename_type (BINFO_TYPE (binfo), name, name, TREE_TYPE (rval)); return TYPE_STUB_DECL (entry); } return rval; } /* Try to find NAME inside a nested class. */ tree lookup_nested_field (name, complain) tree name; int complain; { register tree t; tree id = NULL_TREE; if (TYPE_MAIN_DECL (current_class_type)) { /* Climb our way up the nested ladder, seeing if we're trying to modify a field in an enclosing class. If so, we should only be able to modify if it's static. */ for (t = TYPE_MAIN_DECL (current_class_type); t && DECL_CONTEXT (t); t = TYPE_MAIN_DECL (DECL_CONTEXT (t))) { if (TREE_CODE (DECL_CONTEXT (t)) != RECORD_TYPE) break; /* N.B.: lookup_field will do the access checking for us */ id = lookup_field (DECL_CONTEXT (t), name, complain, 0); if (id == error_mark_node) { id = NULL_TREE; continue; } if (id != NULL_TREE) { if (TREE_CODE (id) == FIELD_DECL && ! TREE_STATIC (id) && TREE_TYPE (id) != error_mark_node) { if (complain) { /* At parse time, we don't want to give this error, since we won't have enough state to make this kind of decision properly. But there are times (e.g., with enums in nested classes) when we do need to call this fn at parse time. So, in those cases, we pass complain as a 0 and just return a NULL_TREE. */ cp_error ("assignment to non-static member `%D' of enclosing class `%T'", id, DECL_CONTEXT (t)); /* Mark this for do_identifier(). It would otherwise claim that the variable was undeclared. */ TREE_TYPE (id) = error_mark_node; } else { id = NULL_TREE; continue; } } break; } } } 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 = CLASS_TYPE_P (type) ? CLASSTYPE_METHOD_VEC (type) : NULL_TREE; 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 /* GATHER_STATISTICS */ /* Constructors are first... */ if (*methods && name == ctor_identifier) return 0; /* and destructors are second. */ if (*++methods && name == dtor_identifier) return 1; while (++methods != end && *methods) { #ifdef GATHER_STATISTICS n_outer_fields_searched++; #endif /* GATHER_STATISTICS */ if (DECL_NAME (OVL_CURRENT (*methods)) == name) break; } /* If we didn't find it, it might have been a template conversion operator. (Note that we don't look for this case above so that we will always find specializations first.) */ if ((methods == end || !*methods) && IDENTIFIER_TYPENAME_P (name)) { methods = &TREE_VEC_ELT (method_vec, 0) + 1; while (++methods != end && *methods) { tree method_name = DECL_NAME (OVL_CURRENT (*methods)); if (!IDENTIFIER_TYPENAME_P (method_name)) { /* Since all conversion operators come first, we know there is no such operator. */ methods = end; break; } else if (TREE_CODE (OVL_CURRENT (*methods)) == TEMPLATE_DECL) break; } } if (methods != end && *methods) return methods - &TREE_VEC_ELT (method_vec, 0); } 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 a given type which have name NAME. No access information is computed by this function, other then to adorn the list of basetypes with TREE_VIA_PUBLIC. If there are two ways to find a name (two members), if COMPLAIN is non-zero, then error_mark_node is returned, and an error message is printed, otherwise, just an error_mark_node is returned. As a special case, is COMPLAIN is -1, we don't complain, and we don't return error_mark_node, but rather the complete list of virtuals. This is used by get_virtuals_named_this. */ tree lookup_fnfields (basetype_path, name, complain) tree basetype_path, name; int complain; { int head = 0, tail = 0; tree type, rval, rval_binfo = NULL_TREE, rvals = NULL_TREE; tree rval_binfo_h = NULL_TREE, binfo, basetype_chain, binfo_h; int idx, find_all = 0; /* rval_binfo is the binfo associated with the found member, note, this can be set with useful information, even when rval is not set, because it must deal with ALL members, not just function members. It is used for ambiguity checking and the hidden checks. Whereas rval is only set if a proper (not hidden) function member is found. */ /* rval_binfo_h and binfo_h are binfo values used when we perform the hiding checks, as virtual base classes may not be shared. The strategy is we always go into the binfo hierarchy owned by TYPE_BINFO of virtual base classes, as we cross virtual base class lines. This way we know that binfo of a virtual base class will always == itself when found along any line. (mrs) */ /* For now, don't try this. */ int protect = complain; char *errstr = 0; if (complain == -1) { find_all = 1; protect = complain = 0; } #if 0 /* We cannot search for constructor/destructor names like this. */ /* This can't go here, but where should it go? */ /* If we are looking for a constructor in a templated type, use the unspecialized name, as that is how we store it. */ if (IDENTIFIER_TEMPLATE (name)) name = constructor_name (name); #endif binfo = basetype_path; binfo_h = binfo; type = complete_type (BINFO_TYPE (basetype_path)); #ifdef GATHER_STATISTICS n_calls_lookup_fnfields++; #endif /* GATHER_STATISTICS */ idx = lookup_fnfields_here (type, name); if (idx >= 0 || lookup_field_1 (type, name)) { rval_binfo = basetype_path; rval_binfo_h = rval_binfo; } if (idx >= 0) { rval = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), idx); rvals = scratch_tree_cons (basetype_path, rval, rvals); if (BINFO_BASETYPES (binfo) && CLASSTYPE_BASELINK_VEC (type)) TREE_TYPE (rvals) = TREE_VEC_ELT (CLASSTYPE_BASELINK_VEC (type), idx); return rvals; } rval = NULL_TREE; if (name == ctor_identifier || name == dtor_identifier) { /* Don't allow lookups of constructors and destructors to go deeper than the first place we look. */ return NULL_TREE; } if (basetype_path == TYPE_BINFO (type)) { basetype_chain = CLASSTYPE_BINFO_AS_LIST (type); my_friendly_assert (BINFO_INHERITANCE_CHAIN (basetype_path) == NULL_TREE, 980827); } else basetype_chain = build_expr_list (NULL_TREE, basetype_path); /* The ambiguity check relies upon breadth first searching. */ search_stack = push_search_level (search_stack, &search_obstack); binfo = basetype_path; binfo_h = binfo; while (1) { tree binfos = BINFO_BASETYPES (binfo); int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0; int idx; /* Process and/or queue base types. */ for (i = 0; i < n_baselinks; i++) { tree base_binfo = TREE_VEC_ELT (binfos, i); if (BINFO_FIELDS_MARKED (base_binfo) == 0) { tree btypes; SET_BINFO_FIELDS_MARKED (base_binfo); btypes = scratch_tree_cons (NULL_TREE, base_binfo, basetype_chain); if (TREE_VIA_VIRTUAL (base_binfo)) btypes = scratch_tree_cons (NULL_TREE, TYPE_BINFO (BINFO_TYPE (TREE_VEC_ELT (BINFO_BASETYPES (binfo_h), i))), btypes); else btypes = scratch_tree_cons (NULL_TREE, TREE_VEC_ELT (BINFO_BASETYPES (binfo_h), i), btypes); obstack_ptr_grow (&search_obstack, btypes); tail += 1; if (tail >= search_stack->limit) my_friendly_abort (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)) my_friendly_assert ((BINFO_INHERITANCE_CHAIN (basetype_path) == TREE_VALUE (TREE_CHAIN (basetype_chain))) /* We only approximate base info for partial instantiations. */ || current_template_parms, 980827); else my_friendly_assert (BINFO_INHERITANCE_CHAIN (basetype_path) == NULL_TREE, 980827); 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 valid. */ idx = lookup_fnfields_here (type, name); if (idx >= 0 || (lookup_field_1 (type, name)!=NULL_TREE && !find_all)) { if (rval_binfo && !find_all && hides (rval_binfo_h, binfo_h)) { /* This is ok, the member found is in rval_binfo, not here (binfo). */ } else if (rval_binfo==NULL_TREE || find_all || hides (binfo_h, rval_binfo_h)) { /* This is ok, the member found is here (binfo), not in rval_binfo. */ if (idx >= 0) { rval = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), idx); /* Note, rvals can only be previously set if find_all is true. */ rvals = scratch_tree_cons (basetype_path, rval, rvals); if (TYPE_BINFO_BASETYPES (type) && CLASSTYPE_BASELINK_VEC (type)) TREE_TYPE (rvals) = TREE_VEC_ELT (CLASSTYPE_BASELINK_VEC (type), idx); } else { /* Undo finding it before, as something else hides it. */ rval = NULL_TREE; rvals = NULL_TREE; } rval_binfo = binfo; rval_binfo_h = binfo_h; } else { /* This is ambiguous. */ errstr = "request for method `%D' is ambiguous"; rvals = error_mark_node; break; } } } { tree *tp = search_stack->first; tree *search_tail = tp + tail; while (tp < search_tail) { CLEAR_BINFO_FIELDS_MARKED (TREE_VALUE (TREE_CHAIN (*tp))); tp += 1; } } search_stack = pop_search_level (search_stack); if (errstr && protect) { cp_error (errstr, name); rvals = error_mark_node; } return rvals; } /* Look for a field or function named NAME in an inheritance lattice dominated by XBASETYPE. PROTECT is zero if we can avoid computing access information, otherwise it is 1. WANT_TYPE is 1 when we should only return TYPE_DECLs, if no TYPE_DECL can be found return NULL_TREE. */ tree lookup_member (xbasetype, name, protect, want_type) tree xbasetype, name; int protect, want_type; { tree ret, basetype_path; if (TREE_CODE (xbasetype) == TREE_VEC) basetype_path = xbasetype; else if (IS_AGGR_TYPE_CODE (TREE_CODE (xbasetype))) { basetype_path = TYPE_BINFO (xbasetype); my_friendly_assert (BINFO_INHERITANCE_CHAIN (basetype_path) == NULL_TREE, 980827); } else my_friendly_abort (97); ret = lookup_field (basetype_path, name, protect, want_type); if (! ret && ! want_type) ret = lookup_fnfields (basetype_path, name, protect); return ret; } /* BREADTH-FIRST SEARCH ROUTINES. */ /* Search a multiple inheritance hierarchy by breadth-first search. BINFO is an aggregate type, possibly in a multiple-inheritance hierarchy. TESTFN is a function, which, if true, means that our condition has been met, and its return value should be returned. QFN, if non-NULL, is a predicate dictating whether the type should even be queued. */ static tree breadth_first_search (binfo, testfn, qfn) tree binfo; tree (*testfn) PROTO((tree)); int (*qfn) PROTO((tree)); { int head = 0, tail = 0; tree rval = NULL_TREE; search_stack = push_search_level (search_stack, &search_obstack); SET_BINFO_MARKED (binfo); obstack_ptr_grow (&search_obstack, binfo); ++tail; while (1) { tree binfos = BINFO_BASETYPES (binfo); int n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0; int i; /* Process and/or queue base types. */ for (i = 0; i < n_baselinks; i++) { tree base_binfo = TREE_VEC_ELT (binfos, i); if (BINFO_MARKED (base_binfo) == 0 && (qfn == 0 || (*qfn) (base_binfo))) { SET_BINFO_MARKED (base_binfo); obstack_ptr_grow (&search_obstack, base_binfo); ++tail; if (tail >= search_stack->limit) my_friendly_abort (100); } } /* Process head of queue, if one exists. */ if (head >= tail) { rval = 0; break; } binfo = search_stack->first[head++]; if ((rval = (*testfn) (binfo))) break; } { tree *tp = search_stack->first; tree *search_tail = tp + tail; while (tp < search_tail) { tree binfo = *tp++; CLEAR_BINFO_MARKED (binfo); } } search_stack = pop_search_level (search_stack); return rval; } /* Functions to use in breadth first searches. */ typedef tree (*pfi) PROTO((tree)); 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 = OVL_NEXT (fndecl)) if (DECL_VINDEX (OVL_CURRENT (fndecl))) return fields; fields = next_baselink (fields); } return NULL_TREE; } static tree get_virtual_destructor (binfo) tree binfo; { tree type = BINFO_TYPE (binfo); if (TYPE_HAS_DESTRUCTOR (type) && DECL_VINDEX (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), 1))) return TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), 1); return 0; } static int tree_has_any_destructor_p (binfo) tree binfo; { tree type = BINFO_TYPE (binfo); return TYPE_NEEDS_DESTRUCTOR (type); } /* Returns > 0 if a function with type DRETTYPE overriding a function with type BRETTYPE is covariant, as defined in [class.virtual]. Returns 1 if trivial covariance, 2 if non-trivial (requiring runtime adjustment), or -1 if pedantically invalid covariance. */ static int covariant_return_p (brettype, drettype) tree brettype, drettype; { tree binfo; if (TREE_CODE (brettype) == FUNCTION_DECL || TREE_CODE (brettype) == THUNK_DECL) { brettype = TREE_TYPE (TREE_TYPE (brettype)); drettype = TREE_TYPE (TREE_TYPE (drettype)); } else if (TREE_CODE (brettype) == METHOD_TYPE) { brettype = TREE_TYPE (brettype); drettype = TREE_TYPE (drettype); } if (same_type_p (brettype, drettype)) return 0; if (! (TREE_CODE (brettype) == TREE_CODE (drettype) && (TREE_CODE (brettype) == POINTER_TYPE || TREE_CODE (brettype) == REFERENCE_TYPE) && TYPE_QUALS (brettype) == TYPE_QUALS (drettype))) return 0; if (! can_convert (brettype, drettype)) return 0; brettype = TREE_TYPE (brettype); drettype = TREE_TYPE (drettype); /* If not pedantic, allow any standard pointer conversion. */ if (! IS_AGGR_TYPE (drettype) || ! IS_AGGR_TYPE (brettype)) return -1; binfo = get_binfo (brettype, drettype, 1); /* If we get an error_mark_node from get_binfo, it already complained, so let's just succeed. */ if (binfo == error_mark_node) return 1; if (! BINFO_OFFSET_ZEROP (binfo) || TREE_VIA_VIRTUAL (binfo)) return 2; return 1; } /* Given a class type TYPE, and a function decl FNDECL, look for a virtual function in TYPE's hierarchy which FNDECL could match as a virtual function. It doesn't matter which one we find. DTORP is nonzero if we are looking for a destructor. Destructors need special treatment because they do not match by name. */ tree get_matching_virtual (binfo, fndecl, dtorp) tree binfo, fndecl; int dtorp; { tree tmp = NULL_TREE; int i; if (TREE_CODE (fndecl) == TEMPLATE_DECL) /* In [temp.mem] we have: A specialization of a member function template does not override a virtual function from a base class. */ return NULL_TREE; /* Breadth first search routines start searching basetypes of TYPE, so we must perform first ply of search here. */ if (dtorp) { return breadth_first_search (binfo, get_virtual_destructor, tree_has_any_destructor_p); } 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; baselink = get_virtuals_named_this (binfo); if (baselink == NULL_TREE) 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; baselink = next_baselink (baselink)) { tree tmps; for (tmps = TREE_VALUE (baselink); tmps; tmps = OVL_NEXT (tmps)) { tmp = OVL_CURRENT (tmps); if (! DECL_VINDEX (tmp)) continue; btypes = TYPE_ARG_TYPES (TREE_TYPE (tmp)); if (instptr_type == NULL_TREE) { if (compparms (TREE_CHAIN (btypes), dtypes)) /* Caller knows to give error in this case. */ return tmp; return NULL_TREE; } if (/* The first parameter is the `this' parameter, which has POINTER_TYPE, and we can therefore safely use TYPE_QUALS, rather than CP_TYPE_QUALS. */ (TYPE_QUALS (TREE_TYPE (TREE_VALUE (btypes))) == TYPE_QUALS (instptr_type)) && compparms (TREE_CHAIN (btypes), TREE_CHAIN (dtypes))) { tree brettype = TREE_TYPE (TREE_TYPE (tmp)); if (same_type_p (brettype, drettype)) /* OK */; else if ((i = covariant_return_p (brettype, drettype))) { if (i == 2) sorry ("adjusting pointers for covariant returns"); if (pedantic && i == -1) { cp_pedwarn_at ("invalid covariant return type for `%#D' (must be pointer or reference to class)", fndecl); cp_pedwarn_at (" overriding `%#D'", tmp); } } else if (IS_AGGR_TYPE_2 (brettype, drettype) && same_or_base_type_p (brettype, drettype)) { error ("invalid covariant return type (must use pointer or reference)"); cp_error_at (" overriding `%#D'", tmp); cp_error_at (" with `%#D'", fndecl); } else if (IDENTIFIER_ERROR_LOCUS (name) == NULL_TREE) { cp_error_at ("conflicting return type specified for virtual function `%#D'", fndecl); cp_error_at (" overriding definition as `%#D'", tmp); SET_IDENTIFIER_ERROR_LOCUS (name, basetype); } break; } } /* If not at the end */ if (tmps) { best = tmp; break; } } return best; } } /* Return the list of virtual functions which are abstract in type TYPE that come from non virtual base classes. See expand_direct_vtbls_init for the style of search we do. */ static tree get_abstract_virtuals_1 (binfo, do_self, abstract_virtuals) tree binfo; int do_self; tree abstract_virtuals; { tree binfos = BINFO_BASETYPES (binfo); int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0; for (i = 0; i < n_baselinks; i++) { tree base_binfo = TREE_VEC_ELT (binfos, i); int is_not_base_vtable = i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo)); if (! TREE_VIA_VIRTUAL (base_binfo)) abstract_virtuals = get_abstract_virtuals_1 (base_binfo, is_not_base_vtable, abstract_virtuals); } /* Should we use something besides CLASSTYPE_VFIELDS? */ if (do_self && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo))) { tree virtuals = BINFO_VIRTUALS (binfo); skip_rtti_stuff (&virtuals); while (virtuals) { tree base_pfn = FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (virtuals)); tree base_fndecl = TREE_OPERAND (base_pfn, 0); if (DECL_ABSTRACT_VIRTUAL_P (base_fndecl)) abstract_virtuals = tree_cons (NULL_TREE, base_fndecl, abstract_virtuals); virtuals = TREE_CHAIN (virtuals); } } return abstract_virtuals; } /* Return the list of virtual functions which are abstract in type TYPE. This information is cached, and so must be built on a non-temporary obstack. */ tree get_abstract_virtuals (type) tree type; { tree vbases; tree abstract_virtuals = CLASSTYPE_ABSTRACT_VIRTUALS (type); /* First get all from non-virtual bases. */ abstract_virtuals = get_abstract_virtuals_1 (TYPE_BINFO (type), 1, abstract_virtuals); for (vbases = CLASSTYPE_VBASECLASSES (type); vbases; vbases = TREE_CHAIN (vbases)) { tree virtuals = BINFO_VIRTUALS (vbases); skip_rtti_stuff (&virtuals); while (virtuals) { tree base_pfn = FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (virtuals)); tree base_fndecl = TREE_OPERAND (base_pfn, 0); if (DECL_NEEDS_FINAL_OVERRIDER_P (base_fndecl)) cp_error ("`%#D' needs a final overrider", base_fndecl); else if (DECL_ABSTRACT_VIRTUAL_P (base_fndecl)) abstract_virtuals = tree_cons (NULL_TREE, base_fndecl, abstract_virtuals); virtuals = TREE_CHAIN (virtuals); } } 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, idx; 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); idx = lookup_fnfields_1 (type, name); if (idx >= 0) { nval = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (type), idx); rval = hash_tree_cons (0, 0, 0, basetypes, nval, rval); if (TYPE_BINFO_BASETYPES (type) == 0) goto dont_queue; else if (TREE_VEC_LENGTH (TYPE_BINFO_BASETYPES (type)) == 1) { if (CLASSTYPE_BASELINK_VEC (type)) TREE_TYPE (rval) = TREE_VEC_ELT (CLASSTYPE_BASELINK_VEC (type), idx); goto dont_queue; } } 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. */ /* 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); my_friendly_assert (BINFO_INHERITANCE_CHAIN (last) == binfo_of_derived, 980827); my_friendly_assert (BINFO_INHERITANCE_CHAIN (binfo_of_derived) == NULL_TREE, 980827); return build_vbase_path (PLUS_EXPR, build_pointer_type (to_type), expr, last, 1); } /* The main function which implements depth first search. This routine has to remember the path it walked up, when dfs_init_vbase_pointers is the work function, as otherwise there would be no record. */ static void dfs_walk (binfo, fn, qfn) tree binfo; void (*fn) PROTO((tree)); int (*qfn) PROTO((tree)); { tree binfos = BINFO_BASETYPES (binfo); int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0; for (i = 0; i < n_baselinks; i++) { tree base_binfo = TREE_VEC_ELT (binfos, i); if (qfn == 0 || (*qfn)(base_binfo)) { if (TREE_CODE (BINFO_TYPE (base_binfo)) == TEMPLATE_TYPE_PARM || TREE_CODE (BINFO_TYPE (base_binfo)) == TEMPLATE_TEMPLATE_PARM) /* Pass */; else if (fn == dfs_init_vbase_pointers) { /* When traversing an arbitrary MI hierarchy, we need to keep a record of the path we took to get down to the final base type, as otherwise there would be no record of it, and just trying to blindly convert at the bottom would be ambiguous. 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 = CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (base_binfo)); } else { vbase_decl_ptr_intermediate = convert_pointer_to_single_level (BINFO_TYPE (base_binfo), vbase_decl_ptr_intermediate); } dfs_walk (base_binfo, fn, qfn); vbase_decl_ptr_intermediate = saved_vbase_decl_ptr_intermediate; } else dfs_walk (base_binfo, fn, qfn); } } fn (binfo); } /* Like dfs_walk, but only walk until fn returns something, and return that. We also use the real vbase binfos instead of the placeholders in the normal binfo hierarchy. START is the most-derived type for this hierarchy, so that we can find the vbase binfos. */ static tree dfs_search (binfo, fn, start) tree binfo, start; tree (*fn) PROTO((tree)); { tree binfos = BINFO_BASETYPES (binfo); int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0; tree retval; for (i = 0; i < n_baselinks; i++) { tree base_binfo = TREE_VEC_ELT (binfos, i); if (TREE_CODE (BINFO_TYPE (base_binfo)) == TEMPLATE_TYPE_PARM || TREE_CODE (BINFO_TYPE (base_binfo)) == TEMPLATE_TEMPLATE_PARM) /* Pass */; else { if (TREE_VIA_VIRTUAL (base_binfo) && start) base_binfo = binfo_member (BINFO_TYPE (base_binfo), CLASSTYPE_VBASECLASSES (start)); retval = dfs_search (base_binfo, fn, start); if (retval) return retval; } } return fn (binfo); } static int markedp (binfo) tree binfo; { return BINFO_MARKED (binfo); } static int unmarkedp (binfo) tree binfo; { return BINFO_MARKED (binfo) == 0; } #if 0 static int bfs_markedp (binfo, i) tree binfo; int i; { return BINFO_MARKED (BINFO_BASETYPE (binfo, i)); } static int bfs_unmarkedp (binfo, i) tree binfo; int i; { return BINFO_MARKED (BINFO_BASETYPE (binfo, i)) == 0; } static int bfs_marked_vtable_pathp (binfo, i) tree binfo; int i; { return BINFO_VTABLE_PATH_MARKED (BINFO_BASETYPE (binfo, i)); } static int bfs_unmarked_vtable_pathp (binfo, i) tree binfo; int i; { return BINFO_VTABLE_PATH_MARKED (BINFO_BASETYPE (binfo, i)) == 0; } static int bfs_marked_new_vtablep (binfo, i) tree binfo; int i; { return BINFO_NEW_VTABLE_MARKED (BINFO_BASETYPE (binfo, i)); } static int bfs_unmarked_new_vtablep (binfo, i) tree binfo; int i; { return BINFO_NEW_VTABLE_MARKED (BINFO_BASETYPE (binfo, i)) == 0; } #endif static int marked_vtable_pathp (binfo) tree binfo; { return BINFO_VTABLE_PATH_MARKED (binfo); } static int unmarked_vtable_pathp (binfo) tree binfo; { return BINFO_VTABLE_PATH_MARKED (binfo) == 0; } static int marked_new_vtablep (binfo) tree binfo; { return BINFO_NEW_VTABLE_MARKED (binfo); } static int unmarked_new_vtablep (binfo) tree binfo; { return BINFO_NEW_VTABLE_MARKED (binfo) == 0; } static int marked_pushdecls_p (binfo) tree binfo; { return BINFO_PUSHDECLS_MARKED (binfo); } static int unmarked_pushdecls_p (binfo) tree binfo; { return BINFO_PUSHDECLS_MARKED (binfo) == 0; } #if 0 static int dfs_search_slot_nonempty_p (binfo) tree binfo; { return CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (binfo)) != 0; } #endif static int dfs_debug_unmarkedp (binfo) tree binfo; { return CLASSTYPE_DEBUG_REQUESTED (BINFO_TYPE (binfo)) == 0; } /* 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). */ #if 0 static void dfs_mark (binfo) tree binfo; { SET_BINFO_MARKED (binfo); } #endif static void dfs_unmark (binfo) tree binfo; { CLEAR_BINFO_MARKED (binfo); } #if 0 static void dfs_mark_vtable_path (binfo) tree binfo; { SET_BINFO_VTABLE_PATH_MARKED (binfo); } static void dfs_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; } #endif 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 (methods == 0) return; /* If interface info is known, either we've already emitted the debug info or we don't need to. */ if (CLASSTYPE_INTERFACE_KNOWN (t)) return; /* If debug info is requested from this context for this type, supply it. If debug info is requested from another context for this type, see if some third context can supply it. */ if (current_function_decl == NULL_TREE || DECL_CLASS_CONTEXT (current_function_decl) != t) { if (TREE_VEC_ELT (methods, 1)) methods = TREE_VEC_ELT (methods, 1); else if (TREE_VEC_ELT (methods, 0)) methods = TREE_VEC_ELT (methods, 0); else methods = TREE_VEC_ELT (methods, 2); methods = OVL_CURRENT (methods); while (methods) { if (DECL_VINDEX (methods) && DECL_THIS_INLINE (methods) == 0 && DECL_ABSTRACT_VIRTUAL_P (methods) == 0) { /* Somebody, somewhere is going to have to define this virtual function. When they do, they will provide the debugging info. */ return; } methods = TREE_CHAIN (methods); } } /* We cannot rely on some alien method to solve our problems, so we must write out the debug info ourselves. */ TYPE_DECL_SUPPRESS_DEBUG (TYPE_NAME (t)) = 0; rest_of_type_compilation (t, toplevel_bindings_p ()); } /* Attach to the type of the virtual base class, the pointer to the virtual base class, given the global pointer vbase_decl_ptr. We use the global vbase_types. ICK! */ static void dfs_find_vbases (binfo) tree binfo; { tree 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) = build (PLUS_EXPR, build_pointer_type (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 this_vbase_ptr; CLEAR_BINFO_VTABLE_PATH_MARKED (binfo); #if 0 /* See finish_struct_1 for when we can enable this. */ /* If we have a vtable pointer first, skip it. */ if (VFIELD_NAME_P (DECL_NAME (fields))) fields = TREE_CHAIN (fields); #endif if (fields == NULL_TREE || DECL_NAME (fields) == NULL_TREE || ! VBASE_NAME_P (DECL_NAME (fields))) return; this_vbase_ptr = vbase_decl_ptr_intermediate; if (build_pointer_type (type) != TYPE_MAIN_VARIANT (TREE_TYPE (this_vbase_ptr))) my_friendly_abort (125); while (fields && DECL_NAME (fields) && VBASE_NAME_P (DECL_NAME (fields))) { tree ref = build (COMPONENT_REF, TREE_TYPE (fields), build_indirect_ref (this_vbase_ptr, NULL_PTR), fields); tree init = CLASSTYPE_SEARCH_SLOT (TREE_TYPE (TREE_TYPE (fields))); vbase_init_result = tree_cons (binfo_member (TREE_TYPE (TREE_TYPE (fields)), vbase_types), build_modify_expr (ref, NOP_EXPR, init), vbase_init_result); 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 = vbase_decl_ptr_intermediate = decl_ptr; vbase_init_result = NULL_TREE; dfs_walk (binfo, dfs_find_vbases, unmarked_vtable_pathp); dfs_walk (binfo, dfs_init_vbase_pointers, marked_vtable_pathp); dfs_walk (binfo, dfs_clear_vbase_slots, marked_new_vtablep); flag_this_is_variable = old_flag; return vbase_init_result; } return 0; } /* get the virtual context (the vbase that directly contains the DECL_CLASS_CONTEXT of the FNDECL) that the given FNDECL is declared in, or NULL_TREE if there is none. FNDECL must come from a virtual table from a virtual base to ensure that there is only one possible DECL_CLASS_CONTEXT. We know that if there is more than one place (binfo) the fndecl that the declared, they all refer to the same binfo. See get_class_offset_1 for the check that ensures this. */ static tree virtual_context (fndecl, t, vbase) tree fndecl, t, vbase; { tree path; if (get_base_distance (DECL_CLASS_CONTEXT (fndecl), t, 0, &path) < 0) { /* DECL_CLASS_CONTEXT can be ambiguous in t. */ if (get_base_distance (DECL_CLASS_CONTEXT (fndecl), vbase, 0, &path) >= 0) { while (path) { /* Not sure if checking path == vbase is necessary here, but just in case it is. */ if (TREE_VIA_VIRTUAL (path) || path == vbase) return binfo_member (BINFO_TYPE (path), CLASSTYPE_VBASECLASSES (t)); path = BINFO_INHERITANCE_CHAIN (path); } } /* This shouldn't happen, I don't want errors! */ warning ("recoverable compiler error, fixups for virtual function"); return vbase; } while (path) { if (TREE_VIA_VIRTUAL (path)) return binfo_member (BINFO_TYPE (path), CLASSTYPE_VBASECLASSES (t)); path = BINFO_INHERITANCE_CHAIN (path); } return 0; } /* Fixups upcast offsets for one vtable. Entries may stay within the VBASE given, or they may upcast into a direct base, or they may upcast into a different vbase. We only need to do fixups in case 2 and 3. In case 2, we add in the virtual base offset to effect an upcast, in case 3, we add in the virtual base offset to effect an upcast, then subtract out the offset for the other virtual base, to effect a downcast into it. This routine mirrors fixup_vtable_deltas in functionality, though this one is runtime based, and the other is compile time based. Conceivably that routine could be removed entirely, and all fixups done at runtime. VBASE_OFFSETS is an association list of virtual bases that contains offset information for the virtual bases, so the offsets are only calculated once. The offsets are computed by where we think the vbase should be (as noted by the CLASSTYPE_SEARCH_SLOT) minus where the vbase really is. */ static void expand_upcast_fixups (binfo, addr, orig_addr, vbase, vbase_addr, t, vbase_offsets) tree binfo, addr, orig_addr, vbase, vbase_addr, t, *vbase_offsets; { tree virtuals = BINFO_VIRTUALS (binfo); tree vc; tree delta; unsigned HOST_WIDE_INT n; delta = purpose_member (vbase, *vbase_offsets); if (! delta) { delta = CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (vbase)); delta = build (MINUS_EXPR, ptrdiff_type_node, delta, vbase_addr); delta = save_expr (delta); delta = tree_cons (vbase, delta, *vbase_offsets); *vbase_offsets = delta; } n = skip_rtti_stuff (&virtuals); while (virtuals) { tree current_fndecl = TREE_VALUE (virtuals); current_fndecl = FNADDR_FROM_VTABLE_ENTRY (current_fndecl); current_fndecl = TREE_OPERAND (current_fndecl, 0); if (current_fndecl && current_fndecl != abort_fndecl && (vc=virtual_context (current_fndecl, t, vbase)) != vbase) { /* This may in fact need a runtime fixup. */ tree idx = build_int_2 (n, 0); tree vtbl = BINFO_VTABLE (binfo); tree nvtbl = lookup_name (DECL_NAME (vtbl), 0); tree aref, ref, naref; tree old_delta, new_delta; tree init; if (nvtbl == NULL_TREE || nvtbl == IDENTIFIER_GLOBAL_VALUE (DECL_NAME (vtbl))) { /* Dup it if it isn't in local scope yet. */ nvtbl = build_decl (VAR_DECL, DECL_NAME (vtbl), TYPE_MAIN_VARIANT (TREE_TYPE (vtbl))); DECL_ALIGN (nvtbl) = MAX (TYPE_ALIGN (double_type_node), DECL_ALIGN (nvtbl)); TREE_READONLY (nvtbl) = 0; DECL_ARTIFICIAL (nvtbl) = 1; nvtbl = pushdecl (nvtbl); init = NULL_TREE; cp_finish_decl (nvtbl, init, NULL_TREE, 0, LOOKUP_ONLYCONVERTING); /* We don't set DECL_VIRTUAL_P and DECL_CONTEXT on nvtbl because they wouldn't be useful; everything that wants to look at the vtable will look at the decl for the normal vtable. Setting DECL_CONTEXT also screws up decl_function_context. */ init = build (MODIFY_EXPR, TREE_TYPE (nvtbl), nvtbl, vtbl); TREE_SIDE_EFFECTS (init) = 1; expand_expr_stmt (init); /* Update the vtable pointers as necessary. */ ref = build_vfield_ref (build_indirect_ref (addr, NULL_PTR), DECL_CONTEXT (CLASSTYPE_VFIELD (BINFO_TYPE (binfo)))); expand_expr_stmt (build_modify_expr (ref, NOP_EXPR, nvtbl)); } assemble_external (vtbl); aref = build_array_ref (vtbl, idx); naref = build_array_ref (nvtbl, idx); old_delta = build_component_ref (aref, delta_identifier, NULL_TREE, 0); new_delta = build_component_ref (naref, delta_identifier, NULL_TREE, 0); /* This is a upcast, so we have to add the offset for the virtual base. */ old_delta = build_binary_op (PLUS_EXPR, old_delta, TREE_VALUE (delta), 0); if (vc) { /* If this is set, we need to subtract out the delta adjustments for the other virtual base that we downcast into. */ tree vc_delta = purpose_member (vc, *vbase_offsets); if (! vc_delta) { tree vc_addr = convert_pointer_to_real (vc, orig_addr); vc_delta = CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (vc)); vc_delta = build (MINUS_EXPR, ptrdiff_type_node, vc_delta, vc_addr); vc_delta = save_expr (vc_delta); *vbase_offsets = tree_cons (vc, vc_delta, *vbase_offsets); } else vc_delta = TREE_VALUE (vc_delta); /* This is a downcast, so we have to subtract the offset for the virtual base. */ old_delta = build_binary_op (MINUS_EXPR, old_delta, vc_delta, 0); } TREE_READONLY (new_delta) = 0; TREE_TYPE (new_delta) = cp_build_qualified_type (TREE_TYPE (new_delta), CP_TYPE_QUALS (TREE_TYPE (new_delta)) & ~TYPE_QUAL_CONST); expand_expr_stmt (build_modify_expr (new_delta, NOP_EXPR, old_delta)); } ++n; virtuals = TREE_CHAIN (virtuals); } } /* Fixup upcast offsets for all direct vtables. Patterned after expand_direct_vtbls_init. */ static void fixup_virtual_upcast_offsets (real_binfo, binfo, init_self, can_elide, addr, orig_addr, type, vbase, vbase_offsets) tree real_binfo, binfo; int init_self, can_elide; tree addr, orig_addr, type, vbase, *vbase_offsets; { tree real_binfos = BINFO_BASETYPES (real_binfo); tree binfos = BINFO_BASETYPES (binfo); int i, n_baselinks = real_binfos ? TREE_VEC_LENGTH (real_binfos) : 0; for (i = 0; i < n_baselinks; i++) { tree real_base_binfo = TREE_VEC_ELT (real_binfos, i); tree base_binfo = TREE_VEC_ELT (binfos, i); int is_not_base_vtable = i != CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (real_binfo)); if (! TREE_VIA_VIRTUAL (real_base_binfo)) fixup_virtual_upcast_offsets (real_base_binfo, base_binfo, is_not_base_vtable, can_elide, addr, orig_addr, type, vbase, vbase_offsets); } #if 0 /* Before turning this on, make sure it is correct. */ if (can_elide && ! BINFO_MODIFIED (binfo)) return; #endif /* Should we use something besides CLASSTYPE_VFIELDS? */ if (init_self && CLASSTYPE_VFIELDS (BINFO_TYPE (real_binfo))) { tree new_addr = convert_pointer_to_real (binfo, addr); expand_upcast_fixups (real_binfo, new_addr, orig_addr, vbase, addr, type, vbase_offsets); } } /* Build a COMPOUND_EXPR which when expanded will generate the code needed to initialize all the virtual function table slots of all the virtual baseclasses. MAIN_BINFO is the binfo which determines the virtual baseclasses to use; TYPE is the type of the object to which the initialization applies. TRUE_EXP is the true object we are initializing, and DECL_PTR is the pointer to the sub-object we are initializing. When USE_COMPUTED_OFFSETS is non-zero, we can assume that the object was laid out by a top-level constructor and the computed offsets are valid to store vtables. When zero, we must store new vtables through virtual baseclass pointers. We setup and use the globals: vbase_decl_ptr, vbase_types ICK! */ void expand_indirect_vtbls_init (binfo, true_exp, decl_ptr) tree binfo; tree true_exp, decl_ptr; { tree type = BINFO_TYPE (binfo); /* This function executes during the finish_function() segment, AFTER the auto variables and temporary stack space has been marked unused...If space is needed for the virtual function tables, some of them might fit within what the compiler now thinks are available stack slots... These values are actually initialized at the beginnning of the function, so when the automatics use their space, they will overwrite the values that are placed here. Marking all temporary space as unavailable prevents this from happening. */ mark_all_temps_used(); if (TYPE_USES_VIRTUAL_BASECLASSES (type)) { rtx fixup_insns = NULL_RTX; tree vbases = CLASSTYPE_VBASECLASSES (type); vbase_types = vbases; vbase_decl_ptr = true_exp ? build_unary_op (ADDR_EXPR, true_exp, 0) : decl_ptr; dfs_walk (binfo, dfs_find_vbases, unmarked_new_vtablep); /* Initialized with vtables of type TYPE. */ for (; vbases; vbases = TREE_CHAIN (vbases)) { tree addr; addr = convert_pointer_to_vbase (TREE_TYPE (vbases), vbase_decl_ptr); /* Do all vtables from this virtual base. */ /* This assumes that virtual bases can never serve as parent binfos. (in the CLASSTYPE_VFIELD_PARENT sense) */ expand_direct_vtbls_init (vbases, TYPE_BINFO (BINFO_TYPE (vbases)), 1, 0, addr); /* Now we adjust the offsets for virtual functions that cross virtual boundaries on an implicit upcast on vf call so that the layout of the most complete type is used, instead of assuming the layout of the virtual bases from our current type. */ if (flag_vtable_thunks) { /* We don't have dynamic thunks yet! So for now, just fail silently. */ } else { tree vbase_offsets = NULL_TREE; push_to_sequence (fixup_insns); fixup_virtual_upcast_offsets (vbases, TYPE_BINFO (BINFO_TYPE (vbases)), 1, 0, addr, vbase_decl_ptr, type, vbases, &vbase_offsets); fixup_insns = get_insns (); end_sequence (); } } if (fixup_insns) { extern tree in_charge_identifier; tree in_charge_node = lookup_name (in_charge_identifier, 0); if (! in_charge_node) { warning ("recoverable internal compiler error, nobody's in charge!"); in_charge_node = integer_zero_node; } in_charge_node = build_binary_op (EQ_EXPR, in_charge_node, integer_zero_node, 1); expand_start_cond (in_charge_node, 0); emit_insns (fixup_insns); expand_end_cond (); } dfs_walk (binfo, dfs_clear_vbase_slots, marked_new_vtablep); } } /* get virtual base class types. This adds type to the vbase_types list in reverse dfs order. Ordering is very important, so don't change it. */ static void dfs_get_vbase_types (binfo) tree binfo; { if (TREE_VIA_VIRTUAL (binfo) && ! BINFO_VBASE_MARKED (binfo)) { tree new_vbase = make_binfo (integer_zero_node, binfo, BINFO_VTABLE (binfo), BINFO_VIRTUALS (binfo)); TREE_CHAIN (new_vbase) = vbase_types; TREE_VIA_VIRTUAL (new_vbase) = 1; vbase_types = new_vbase; SET_BINFO_VBASE_MARKED (binfo); } SET_BINFO_MARKED (binfo); } /* get a list of virtual base classes in dfs order. */ tree get_vbase_types (type) tree type; { tree vbases; tree binfo; binfo = TYPE_BINFO (type); vbase_types = NULL_TREE; dfs_walk (binfo, dfs_get_vbase_types, unmarkedp); dfs_walk (binfo, dfs_unmark, markedp); /* Rely upon the reverse dfs ordering from dfs_get_vbase_types, and now reverse it so that we get normal dfs ordering. */ vbase_types = nreverse (vbase_types); /* unmark marked vbases */ for (vbases = vbase_types; vbases; vbases = TREE_CHAIN (vbases)) CLEAR_BINFO_VBASE_MARKED (vbases); return vbase_types; } /* 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. Also mark member types. */ void note_debug_info_needed (type) tree type; { tree field; if (current_template_parms) return; if (TYPE_BEING_DEFINED (type)) /* We can't go looking for the base types and fields just yet. */ return; /* We can't do the TYPE_DECL_SUPPRESS_DEBUG thing with DWARF, which does not support name references between translation units. Well, we could, but that would mean putting global labels in the debug output before each exported type and each of its functions and static data members. */ if (write_symbols == DWARF_DEBUG || write_symbols == DWARF2_DEBUG) return; dfs_walk (TYPE_BINFO (type), dfs_debug_mark, dfs_debug_unmarkedp); for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field)) { tree ttype; if (TREE_CODE (field) == FIELD_DECL && IS_AGGR_TYPE (ttype = target_type (TREE_TYPE (field))) && dfs_debug_unmarkedp (TYPE_BINFO (ttype))) note_debug_info_needed (ttype); } } /* Subroutines of push_class_decls (). */ /* Add in a decl to the envelope. */ static void envelope_add_decl (type, decl, values) tree type, decl, *values; { tree context, *tmp; tree name = DECL_NAME (decl); int dont_add = 0; /* Yet Another Implicit Typename Kludge: Since we don't tsubst the members for partial instantiations, DECL_CONTEXT (decl) is wrong. But pretend it's right for this function. */ if (processing_template_decl) type = DECL_REAL_CONTEXT (decl); /* virtual base names are always unique. */ if (VBASE_NAME_P (name)) *values = NULL_TREE; /* Possible ambiguity. If its defining type(s) is (are all) derived from us, no problem. */ else if (*values && TREE_CODE (*values) != TREE_LIST) { tree value = *values; /* Only complain if we shadow something we can access. */ if (warn_shadow && TREE_CODE (decl) == FUNCTION_DECL && ((DECL_LANG_SPECIFIC (*values) && DECL_CLASS_CONTEXT (value) == current_class_type) || ! TREE_PRIVATE (value))) /* Should figure out access control more accurately. */ { cp_warning_at ("member `%#D' is shadowed", value); cp_warning_at ("by member function `%#D'", decl); warning ("in this context"); } context = DECL_REAL_CONTEXT (value); if (context == type) { if (TREE_CODE (value) == TYPE_DECL && DECL_ARTIFICIAL (value)) *values = NULL_TREE; else dont_add = 1; } else if (type == current_class_type || DERIVED_FROM_P (context, type)) { /* Don't add in *values to list */ *values = NULL_TREE; } else *values = build_tree_list (NULL_TREE, value); } else for (tmp = values; *tmp;) { tree value = TREE_VALUE (*tmp); my_friendly_assert (TREE_CODE (value) != TREE_LIST, 999); context = (TREE_CODE (value) == FUNCTION_DECL && DECL_VIRTUAL_P (value)) ? DECL_CLASS_CONTEXT (value) : DECL_CONTEXT (value); if (type == current_class_type || DERIVED_FROM_P (context, type)) { /* remove *tmp from list */ *tmp = TREE_CHAIN (*tmp); } else tmp = &TREE_CHAIN (*tmp); } if (! dont_add) { /* Put the new contents in our envelope. */ if (TREE_CODE (decl) == FUNCTION_DECL) { *values = tree_cons (name, decl, *values); TREE_NONLOCAL_FLAG (*values) = 1; TREE_TYPE (*values) = unknown_type_node; } else { if (*values) { *values = tree_cons (NULL_TREE, decl, *values); /* Mark this as a potentially ambiguous member. */ /* Leaving TREE_TYPE blank is intentional. We cannot use `error_mark_node' (lookup_name) or `unknown_type_node' (all member functions use this). */ TREE_NONLOCAL_FLAG (*values) = 1; } else *values = decl; } } } /* Returns 1 iff BINFO is a base we shouldn't really be able to see into, because it (or one of the intermediate bases) depends on template parms. */ static int dependent_base_p (binfo) tree binfo; { for (; binfo; binfo = BINFO_INHERITANCE_CHAIN (binfo)) { if (TREE_TYPE (binfo) == current_class_type) break; if (uses_template_parms (TREE_TYPE (binfo))) return 1; } return 0; } /* Add the instance variables which this class contributed to the current class binding contour. When a redefinition occurs, if the redefinition is strictly within a single inheritance path, we just overwrite the old declaration with the new. If the fields are not within a single inheritance path, we must cons them. In order to know what decls are new (stemming from the current invocation of push_class_decls) we enclose them in an "envelope", which is a TREE_LIST node where the TREE_PURPOSE slot contains the new decl (or possibly a list of competing ones), the TREE_VALUE slot points to the old value and the TREE_CHAIN slot chains together all envelopes which needs to be "opened" in push_class_decls. Opening an envelope means: push the old value onto the class_shadowed list, install the new one and if it's a TYPE_DECL do the same to the IDENTIFIER_TYPE_VALUE. Such an envelope is recognized by seeing that the TREE_PURPOSE slot is non-null, and that it is not an identifier. Because if it is, it could be a set of overloaded methods from an outer scope. */ static void dfs_pushdecls (binfo) tree binfo; { tree type = BINFO_TYPE (binfo); tree fields; tree method_vec; int dummy = 0; /* Only record types if we're a template base. */ if (processing_template_decl && type != current_class_type && dependent_base_p (binfo)) dummy = 1; for (fields = TYPE_FIELDS (type); fields; fields = TREE_CHAIN (fields)) { if (dummy && TREE_CODE (fields) != TYPE_DECL) continue; /* Unmark so that if we are in a constructor, and then find that this field was initialized by a base initializer, we can emit an error message. */ if (TREE_CODE (fields) == FIELD_DECL) TREE_USED (fields) = 0; /* Recurse into anonymous unions. */ if (DECL_NAME (fields) == NULL_TREE && TREE_CODE (TREE_TYPE (fields)) == UNION_TYPE) { dfs_pushdecls (TYPE_BINFO (TREE_TYPE (fields))); continue; } if (DECL_NAME (fields)) { tree name = DECL_NAME (fields); tree class_value = IDENTIFIER_CLASS_VALUE (name); /* If the class value is not an envelope of the kind described in the comment above, we create a new envelope. */ maybe_push_cache_obstack (); if (class_value == NULL_TREE || TREE_CODE (class_value) != TREE_LIST || TREE_PURPOSE (class_value) == NULL_TREE || TREE_CODE (TREE_PURPOSE (class_value)) == IDENTIFIER_NODE) { /* See comment above for a description of envelopes. */ closed_envelopes = tree_cons (NULL_TREE, class_value, closed_envelopes); IDENTIFIER_CLASS_VALUE (name) = closed_envelopes; class_value = IDENTIFIER_CLASS_VALUE (name); } envelope_add_decl (type, fields, &TREE_PURPOSE (class_value)); pop_obstacks (); } } method_vec = CLASS_TYPE_P (type) ? CLASSTYPE_METHOD_VEC (type) : NULL_TREE; if (method_vec && ! dummy) { tree *methods; tree *end; /* Farm out constructors and destructors. */ end = TREE_VEC_END (method_vec); for (methods = &TREE_VEC_ELT (method_vec, 2); *methods && methods != end; methods++) { /* This will cause lookup_name to return a pointer to the tree_list of possible methods of this name. */ tree name; tree class_value; name = DECL_NAME (OVL_CURRENT (*methods)); class_value = IDENTIFIER_CLASS_VALUE (name); maybe_push_cache_obstack (); /* If the class value is not an envelope of the kind described in the comment above, we create a new envelope. */ if (class_value == NULL_TREE || TREE_CODE (class_value) != TREE_LIST || TREE_PURPOSE (class_value) == NULL_TREE || TREE_CODE (TREE_PURPOSE (class_value)) == IDENTIFIER_NODE) { /* See comment above for a description of envelopes. */ closed_envelopes = tree_cons (NULL_TREE, class_value, closed_envelopes); IDENTIFIER_CLASS_VALUE (name) = closed_envelopes; class_value = IDENTIFIER_CLASS_VALUE (name); } /* Here we try to rule out possible ambiguities. If we can't do that, keep a TREE_LIST with possibly ambiguous decls in there. */ /* Arbitrarily choose the first function in the list. This is OK because this is only used for initial lookup; anything that actually uses the function will look it up again. */ envelope_add_decl (type, OVL_CURRENT (*methods), &TREE_PURPOSE (class_value)); pop_obstacks (); } } /* We can't just use BINFO_MARKED because envelope_add_decl uses DERIVED_FROM_P, which calls get_base_distance. */ SET_BINFO_PUSHDECLS_MARKED (binfo); } /* Consolidate unique (by name) member functions. */ static void dfs_compress_decls (binfo) tree binfo; { tree type = BINFO_TYPE (binfo); tree method_vec = CLASS_TYPE_P (type) ? CLASSTYPE_METHOD_VEC (type) : NULL_TREE; if (processing_template_decl && type != current_class_type && dependent_base_p (binfo)) /* We only record types if we're a template base. */; else if (method_vec != 0) { /* Farm out constructors and destructors. */ tree *methods; tree *end = TREE_VEC_END (method_vec); for (methods = &TREE_VEC_ELT (method_vec, 2); methods != end && *methods; methods++) { /* This is known to be an envelope of the kind described before dfs_pushdecls. */ tree class_value = IDENTIFIER_CLASS_VALUE (DECL_NAME (OVL_CURRENT (*methods))); tree tmp = TREE_PURPOSE (class_value); /* This was replaced in scope by somebody else. Just leave it alone. */ if (TREE_CODE (tmp) != TREE_LIST) continue; if (TREE_CHAIN (tmp) == NULL_TREE && TREE_VALUE (tmp) && OVL_NEXT (TREE_VALUE (tmp)) == NULL_TREE) { TREE_PURPOSE (class_value) = TREE_VALUE (tmp); } } } CLEAR_BINFO_PUSHDECLS_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; { struct obstack *ambient_obstack = current_obstack; search_stack = push_search_level (search_stack, &search_obstack); /* Build up all the relevant bindings and such on the cache obstack. That way no memory is wasted when we throw away the cache later. */ maybe_push_cache_obstack (); /* Push class fields into CLASS_VALUE scope, and mark. */ dfs_walk (TYPE_BINFO (type), dfs_pushdecls, unmarked_pushdecls_p); /* Compress fields which have only a single entry by a given name, and unmark. */ dfs_walk (TYPE_BINFO (type), dfs_compress_decls, marked_pushdecls_p); /* Open up all the closed envelopes and push the contained decls into class scope. */ while (closed_envelopes) { tree new = TREE_PURPOSE (closed_envelopes); tree id; /* This is messy because the class value may be a *_DECL, or a TREE_LIST of overloaded *_DECLs or even a TREE_LIST of ambiguous *_DECLs. The name is stored at different places in these three cases. */ if (TREE_CODE (new) == TREE_LIST) { if (TREE_PURPOSE (new) != NULL_TREE) id = TREE_PURPOSE (new); else { tree node = TREE_VALUE (new); if (TREE_CODE (node) == TYPE_DECL && DECL_ARTIFICIAL (node) && IS_AGGR_TYPE (TREE_TYPE (node)) && CLASSTYPE_TEMPLATE_INFO (TREE_TYPE (node))) { tree t = CLASSTYPE_TI_TEMPLATE (TREE_TYPE (node)); tree n = new; for (; n; n = TREE_CHAIN (n)) { tree d = TREE_VALUE (n); if (TREE_CODE (d) == TYPE_DECL && DECL_ARTIFICIAL (node) && IS_AGGR_TYPE (TREE_TYPE (d)) && CLASSTYPE_TEMPLATE_INFO (TREE_TYPE (d)) && CLASSTYPE_TI_TEMPLATE (TREE_TYPE (d)) == t) /* OK */; else break; } if (n == NULL_TREE) new = t; } else while (TREE_CODE (node) == TREE_LIST) node = TREE_VALUE (node); id = DECL_NAME (node); } } else id = DECL_NAME (new); /* Install the original class value in order to make pushdecl_class_level work correctly. */ IDENTIFIER_CLASS_VALUE (id) = TREE_VALUE (closed_envelopes); if (TREE_CODE (new) == TREE_LIST) push_class_level_binding (id, new); else pushdecl_class_level (new); closed_envelopes = TREE_CHAIN (closed_envelopes); } /* Undo the call to maybe_push_cache_obstack above. */ pop_obstacks (); current_obstack = ambient_obstack; } /* Here's a subroutine we need because C lacks lambdas. */ static void dfs_unuse_fields (binfo) tree binfo; { tree type = TREE_TYPE (binfo); tree fields; for (fields = TYPE_FIELDS (type); fields; fields = TREE_CHAIN (fields)) { if (TREE_CODE (fields) != FIELD_DECL) continue; TREE_USED (fields) = 0; if (DECL_NAME (fields) == NULL_TREE && TREE_CODE (TREE_TYPE (fields)) == UNION_TYPE) unuse_fields (TREE_TYPE (fields)); } } void unuse_fields (type) tree type; { dfs_walk (TYPE_BINFO (type), dfs_unuse_fields, unmarkedp); } void pop_class_decls () { /* We haven't pushed a search level when dealing with cached classes, so we'd better not try to pop it. */ if (search_stack) search_stack = pop_search_level (search_stack); } void print_search_statistics () { #ifdef GATHER_STATISTICS 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 /* GATHER_STATISTICS */ fprintf (stderr, "no search statistics\n"); #endif /* GATHER_STATISTICS */ } void init_search_processing () { gcc_obstack_init (&search_obstack); _vptr_name = get_identifier ("_vptr"); } void reinit_search_statistics () { #ifdef GATHER_STATISTICS n_fields_searched = 0; n_calls_lookup_field = 0, n_calls_lookup_field_1 = 0; n_calls_lookup_fnfields = 0, n_calls_lookup_fnfields_1 = 0; n_calls_get_base_type = 0; n_outer_fields_searched = 0; n_contexts_saved = 0; #endif /* GATHER_STATISTICS */ } #define scratch_tree_cons expr_tree_cons static tree conversions; static tree add_conversions (binfo) tree binfo; { int i; tree method_vec = CLASSTYPE_METHOD_VEC (BINFO_TYPE (binfo)); tree name = NULL_TREE; for (i = 2; i < TREE_VEC_LENGTH (method_vec); ++i) { tree tmp = TREE_VEC_ELT (method_vec, i); if (!tmp || ! DECL_CONV_FN_P (OVL_CURRENT (tmp))) break; /* We don't want to mark 'name' until we've seen all the overloads in this class; we could be overloading on the quals of 'this'. */ if (name && name != DECL_NAME (tmp)) { IDENTIFIER_MARKED (name) = 1; name = NULL_TREE; } /* Make sure we don't already have this conversion. */ if (! IDENTIFIER_MARKED (DECL_NAME (tmp))) { conversions = scratch_tree_cons (binfo, tmp, conversions); name = DECL_NAME (tmp); } } if (name) IDENTIFIER_MARKED (name) = 1; return NULL_TREE; } tree lookup_conversions (type) tree type; { tree t; conversions = NULL_TREE; if (TYPE_SIZE (type)) breadth_first_search (TYPE_BINFO (type), add_conversions, 0); for (t = conversions; t; t = TREE_CHAIN (t)) IDENTIFIER_MARKED (DECL_NAME (TREE_VALUE (t))) = 0; return conversions; } /* Subroutine of get_template_base. */ static tree get_template_base_recursive (binfo, rval, template, via_virtual) tree binfo, template, rval; int via_virtual; { tree binfos; int i, n_baselinks; tree type = BINFO_TYPE (binfo); if (CLASSTYPE_TEMPLATE_INFO (type) && CLASSTYPE_TI_TEMPLATE (type) == template) { if (rval == NULL_TREE || rval == type) return type; else return error_mark_node; } binfos = BINFO_BASETYPES (binfo); n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0; /* Process base types. */ for (i = 0; i < n_baselinks; i++) { tree base_binfo = TREE_VEC_ELT (binfos, i); /* Find any specific instance of a virtual base, when searching with a binfo... */ if (BINFO_MARKED (base_binfo) == 0) { int this_virtual = via_virtual || TREE_VIA_VIRTUAL (base_binfo); /* When searching for a non-virtual, we cannot mark virtually found binfos. */ if (! this_virtual) SET_BINFO_MARKED (base_binfo); rval = get_template_base_recursive (base_binfo, rval, template, this_virtual); if (rval == error_mark_node) return rval; } } return rval; } /* Given a class template TEMPLATE and a class type or binfo node BINFO, find the unique base type in BINFO that is an instance of TEMPLATE. If there are more than one, return error_mark_node. Used by unify. */ tree get_template_base (template, binfo) register tree template, binfo; { tree type = NULL_TREE, rval; if (TREE_CODE (binfo) == TREE_VEC) type = BINFO_TYPE (binfo); else if (IS_AGGR_TYPE_CODE (TREE_CODE (binfo))) { type = complete_type (binfo); binfo = TYPE_BINFO (type); } else my_friendly_abort (92); if (CLASSTYPE_TEMPLATE_INFO (type) && CLASSTYPE_TI_TEMPLATE (type) == template) return type; rval = get_template_base_recursive (binfo, NULL_TREE, template, 0); dfs_walk (binfo, dfs_unmark, markedp); return rval; } /* Check whether the empty class indicated by EMPTY_BINFO is also present at offset 0 in COMPARE_TYPE, and set found_overlap if so. */ static tree compare_type; static int found_overlap; static void dfs_check_overlap (empty_binfo) tree empty_binfo; { tree binfo; for (binfo = TYPE_BINFO (compare_type); ; binfo = BINFO_BASETYPE (binfo, 0)) { if (BINFO_TYPE (binfo) == BINFO_TYPE (empty_binfo)) { found_overlap = 1; break; } else if (BINFO_BASETYPES (binfo) == NULL_TREE) break; } } /* Trivial function to stop base traversal when we find something. */ static int dfs_no_overlap_yet (t) tree t ATTRIBUTE_UNUSED; { return found_overlap == 0; } /* Returns nonzero if EMPTY_TYPE or any of its bases can also be found at offset 0 in NEXT_TYPE. Used in laying out empty base class subobjects. */ int types_overlap_p (empty_type, next_type) tree empty_type, next_type; { if (! IS_AGGR_TYPE (next_type)) return 0; compare_type = next_type; found_overlap = 0; dfs_walk (TYPE_BINFO (empty_type), dfs_check_overlap, dfs_no_overlap_yet); return found_overlap; } /* Passed to dfs_search by binfo_for_vtable; determine if bvtable comes from BINFO. */ static tree bvtable; static tree dfs_bfv_helper (binfo) tree binfo; { if (BINFO_VTABLE (binfo) == bvtable) return binfo; return NULL_TREE; } /* Given a vtable VARS, determine which binfo it comes from. */ tree binfo_for_vtable (vars) tree vars; { bvtable = vars; return dfs_search (TYPE_BINFO (DECL_CONTEXT (vars)), dfs_bfv_helper, DECL_CONTEXT (vars)); }