--- gcc/cp/search.c 2018/04/24 18:20:21 1.1.1.1 +++ gcc/cp/search.c 2018/04/24 18:27:09 1.1.1.2 @@ -1,6 +1,6 @@ /* Breadth-first and depth-first routines for searching multiple-inheritance lattice for GNU C++. - Copyright (C) 1987, 1989, 1992, 1993 Free Software Foundation, Inc. + Copyright (C) 1987, 89, 92, 93, 94, 1995 Free Software Foundation, Inc. Contributed by Michael Tiemann (tiemann@cygnus.com) This file is part of GNU CC. @@ -17,7 +17,8 @@ GNU General Public License for more deta You should have received a copy of the GNU General Public License along with GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ /* High-level class interface. */ @@ -27,12 +28,15 @@ the Free Software Foundation, 675 Mass A #include "cp-tree.h" #include "obstack.h" #include "flags.h" +#include "rtl.h" +#include "output.h" #define obstack_chunk_alloc xmalloc #define obstack_chunk_free free void init_search (); extern struct obstack *current_obstack; +extern tree abort_fndecl; #include "stack.h" @@ -377,8 +381,67 @@ pop_memoized_context (use_old) type_stack = (struct type_level *)type_stack->base.prev; } -#if 0 /* unused */ +/* Get a virtual binfo that is found inside BINFO's hierarchy that is + the same type as the type given in PARENT. To be optimal, we want + the first one that is found by going through the least number of + virtual bases. DEPTH should be NULL_PTR. */ +static tree +get_vbase (parent, binfo, depth) + tree parent, binfo; + unsigned int *depth; +{ + tree binfos; + int i, n_baselinks; + tree rval = NULL_TREE; + + if (depth == 0) + { + unsigned int d = (unsigned int)-1; + return get_vbase (parent, binfo, &d); + } + + if (BINFO_TYPE (binfo) == parent && TREE_VIA_VIRTUAL (binfo)) + { + *depth = 0; + 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 (parent, base_binfo, depth); + if (nrval) + rval = nrval; + } + *depth = *depth+1; + return rval; +} + +/* Convert EXPR to a virtual base class of type TYPE. We know that + EXPR is a non-null POINTER_TYPE to RECORD_TYPE. We also know that + the type of what expr points to has a virtual base of type TYPE. */ +tree +convert_pointer_to_vbase (type, expr) + tree type; + tree expr; +{ + tree vb = get_vbase (type, TYPE_BINFO (TREE_TYPE (TREE_TYPE (expr))), NULL_PTR); + return convert_pointer_to_real (vb, expr); +} + /* This is the newer recursive depth first search routine. */ +#if 0 /* unused */ /* Return non-zero if PARENT is directly derived from TYPE. By directly we mean it's only one step up the inheritance lattice. We check this by walking horizontally across the types that TYPE directly inherits @@ -427,18 +490,13 @@ get_binfo (parent, binfo, protect) if (TREE_CODE (parent) == TREE_VEC) parent = BINFO_TYPE (parent); - /* unions cannot participate in inheritance relationships */ - else if (TREE_CODE (parent) == UNION_TYPE) - return NULL_TREE; - else if (TREE_CODE (parent) != RECORD_TYPE) + 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 (TREE_CODE (binfo) == RECORD_TYPE) + else if (IS_AGGR_TYPE_CODE (TREE_CODE (binfo))) type = binfo; - else if (TREE_CODE (binfo) == UNION_TYPE) - return NULL_TREE; else my_friendly_abort (90); @@ -568,7 +626,7 @@ get_base_distance_recursive (binfo, dept Return -3 if PARENT is private to TYPE, and PROTECT is non-zero. If PATH_PTR is non-NULL, then also build the list of types - from PARENT to TYPE, with TREE_VIA_VIRUAL and TREE_VIA_PUBLIC + 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 @@ -798,6 +856,10 @@ compute_access (basetype_path, field) } #endif + /* We don't currently support access control on nested types. */ + if (TREE_CODE (field) == TYPE_DECL) + return access_public; + previous_scope = current_scope (); context = DECL_CLASS_CONTEXT (field); @@ -1089,18 +1151,29 @@ lookup_field (xbasetype, name, protect, entry = 0; rval = lookup_field_1 (type, name); - if (rval || lookup_fnfields_here (type, name)>=0) - { - rval_binfo = basetype_path; - rval_binfo_h = rval_binfo; - } - - if (rval && TREE_CODE (rval) != TYPE_DECL && want_type) - rval = NULL_TREE; - if (rval) + if (rval || lookup_fnfields_here (type, name) >= 0) { - if (protect) + 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); @@ -1207,7 +1280,7 @@ lookup_field (xbasetype, name, protect, /* See if we can find NAME in TYPE. If RVAL is nonzero, and we do find NAME in TYPE, verify that such a second - sighting is in fact legal. */ + sighting is in fact valid. */ nval = lookup_field_1 (type, name); @@ -1259,12 +1332,33 @@ lookup_field (xbasetype, name, protect, if (entry) TREE_VALUE (entry) = rval; - if (want_type && (rval == NULL_TREE || TREE_CODE (rval) != TYPE_DECL)) + if (rval_binfo) { - rval = NULL_TREE; - errstr = 0; + 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) || entry) @@ -1662,7 +1756,7 @@ lookup_fnfields (basetype_path, name, co /* See if we can find NAME in TYPE. If RVAL is nonzero, and we do find NAME in TYPE, verify that such a second - sighting is in fact legal. */ + sighting is in fact valid. */ index = lookup_fnfields_here (type, name); @@ -1948,11 +2042,51 @@ get_matching_virtual (binfo, fndecl, dto == TYPE_READONLY (instptr_type)) && compparms (TREE_CHAIN (btypes), TREE_CHAIN (dtypes), 3)) { - if (IDENTIFIER_ERROR_LOCUS (name) == NULL_TREE - && ! comptypes (TREE_TYPE (TREE_TYPE (tmp)), drettype, 1)) + tree brettype = TREE_TYPE (TREE_TYPE (tmp)); + if (comptypes (brettype, drettype, 1)) + /* OK */; + else if + (TREE_CODE (brettype) == TREE_CODE (drettype) + && (TREE_CODE (brettype) == POINTER_TYPE + || TREE_CODE (brettype) == REFERENCE_TYPE) + && comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (brettype)), + TYPE_MAIN_VARIANT (TREE_TYPE (drettype)), + 0)) + /* covariant return type */ + { + tree b = TREE_TYPE (brettype), d = TREE_TYPE (drettype); + if (TYPE_MAIN_VARIANT (b) != TYPE_MAIN_VARIANT (d)) + { + tree binfo = get_binfo (b, d, 1); + if (binfo != error_mark_node + && ! BINFO_OFFSET_ZEROP (binfo)) + sorry ("adjusting pointers for covariant returns"); + } + if (TYPE_READONLY (d) > TYPE_READONLY (b)) + { + cp_error ("return type of `%#D' adds const", fndecl); + cp_error_at (" overriding definition as `%#D'", + tmp); + } + else if (TYPE_VOLATILE (d) > TYPE_VOLATILE (b)) + { + cp_error ("return type of `%#D' adds volatile", + fndecl); + cp_error_at (" overriding definition as `%#D'", + tmp); + } + } + else if (IS_AGGR_TYPE_2 (brettype, drettype) + && comptypes (brettype, drettype, 0)) + { + error ("invalid covariant return type (must use pointer or reference)"); + cp_error_at (" overriding `%#D'", tmp); + cp_error (" with `%#D'", fndecl); + } + else if (IDENTIFIER_ERROR_LOCUS (name) == NULL_TREE) { cp_error ("conflicting return type specified for virtual function `%#D'", fndecl); - cp_error_at ("overriding definition as `%#D'", tmp); + cp_error_at (" overriding definition as `%#D'", tmp); SET_IDENTIFIER_ERROR_LOCUS (name, basetype); } break; @@ -1995,19 +2129,17 @@ get_abstract_virtuals_1 (binfo, do_self, /* Should we use something besides CLASSTYPE_VFIELDS? */ if (do_self && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo))) { - tree tmp = TREE_CHAIN (BINFO_VIRTUALS (binfo)); + tree virtuals = BINFO_VIRTUALS (binfo); - /* Get around dossier entry if there is one. */ - if (flag_dossier) - tmp = TREE_CHAIN (tmp); + skip_rtti_stuff (&virtuals); - while (tmp) + while (virtuals) { - tree base_pfn = FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (tmp)); + 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); - tmp = TREE_CHAIN (tmp); + virtuals = TREE_CHAIN (virtuals); } } return abstract_virtuals; @@ -2020,7 +2152,7 @@ tree get_abstract_virtuals (type) tree type; { - tree vbases, tmp; + tree vbases; tree abstract_virtuals = CLASSTYPE_ABSTRACT_VIRTUALS (type); /* First get all from non-virtual bases. */ @@ -2029,17 +2161,17 @@ get_abstract_virtuals (type) for (vbases = CLASSTYPE_VBASECLASSES (type); vbases; vbases = TREE_CHAIN (vbases)) { - if (! BINFO_VIRTUALS (vbases)) - continue; + tree virtuals = BINFO_VIRTUALS (vbases); + + skip_rtti_stuff (&virtuals); - tmp = TREE_CHAIN (BINFO_VIRTUALS (vbases)); - while (tmp) + while (virtuals) { - tree base_pfn = FNADDR_FROM_VTABLE_ENTRY (TREE_VALUE (tmp)); + 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); - tmp = TREE_CHAIN (tmp); + virtuals = TREE_CHAIN (virtuals); } } return nreverse (abstract_virtuals); @@ -2174,7 +2306,7 @@ convert_pointer_to_single_level (to_type last = get_binfo (to_type, TREE_TYPE (TREE_TYPE (expr)), 0); BINFO_INHERITANCE_CHAIN (last) = binfo_of_derived; BINFO_INHERITANCE_CHAIN (binfo_of_derived) = NULL_TREE; - return build_vbase_path (PLUS_EXPR, TYPE_POINTER_TO (to_type), expr, last, 1); + return build_vbase_path (PLUS_EXPR, build_pointer_type (to_type), expr, last, 1); } /* The main function which implements depth first search. @@ -2195,7 +2327,7 @@ dfs_walk (binfo, fn, qfn) { tree base_binfo = TREE_VEC_ELT (binfos, i); - if ((*qfn)(base_binfo)) + if (qfn == 0 || (*qfn)(base_binfo)) { if (fn == dfs_init_vbase_pointers) { @@ -2359,8 +2491,7 @@ dfs_debug_mark (binfo) while (methods) { if (DECL_VINDEX (methods) - && DECL_SAVED_INSNS (methods) == 0 - && DECL_PENDING_INLINE_INFO (methods) == 0 + && DECL_THIS_INLINE (methods) == 0 && DECL_ABSTRACT_VIRTUAL_P (methods) == 0) { /* Somebody, somewhere is going to have to define this @@ -2399,7 +2530,7 @@ dfs_find_vbases (binfo) tree binfo = binfo_member (vbase, vbase_types); CLASSTYPE_SEARCH_SLOT (vbase) - = (char *) build (PLUS_EXPR, TYPE_POINTER_TO (vbase), + = (char *) build (PLUS_EXPR, build_pointer_type (vbase), vbase_decl_ptr, BINFO_OFFSET (binfo)); } } @@ -2417,10 +2548,10 @@ dfs_init_vbase_pointers (binfo) CLEAR_BINFO_VTABLE_PATH_MARKED (binfo); - /* If there is a dossier, it is the first field, though perhaps from + /* If there is a rtti, it is the first field, though perhaps from the base class. Otherwise, the first fields are virtual base class pointer fields. */ - if (CLASSTYPE_DOSSIER (type) && VFIELD_NAME_P (DECL_NAME (fields))) + if (CLASSTYPE_RTTI (type) && VFIELD_NAME_P (DECL_NAME (fields))) /* Get past vtable for the object. */ fields = TREE_CHAIN (fields); @@ -2431,7 +2562,7 @@ dfs_init_vbase_pointers (binfo) this_vbase_ptr = vbase_decl_ptr_intermediate; - if (TYPE_POINTER_TO (type) != TYPE_MAIN_VARIANT (TREE_TYPE (this_vbase_ptr))) + if (build_pointer_type (type) != TYPE_MAIN_VARIANT (TREE_TYPE (this_vbase_ptr))) my_friendly_abort (125); while (fields && DECL_NAME (fields) @@ -2485,6 +2616,195 @@ init_vbase_pointers (type, decl_ptr) 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. + + 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, so the offsets are only calculated once. */ +static void +expand_upcast_fixups (binfo, addr, orig_addr, vbase, t, vbase_offsets) + tree binfo, addr, orig_addr, vbase, 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 = (tree)CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (vbase)); + delta = build (MINUS_EXPR, ptrdiff_type_node, delta, 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 = DECL_VINDEX (current_fndecl); + 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 (BINFO_VTABLE (binfo)))); + DECL_ALIGN (nvtbl) = MAX (TYPE_ALIGN (double_type_node), + DECL_ALIGN (nvtbl)); + TREE_READONLY (nvtbl) = 0; + nvtbl = pushdecl (nvtbl); + init = NULL_TREE; + cp_finish_decl (nvtbl, init, NULL_TREE, 0, LOOKUP_ONLYCONVERTING); + DECL_VIRTUAL_P (nvtbl) = 1; + DECL_CONTEXT (nvtbl) = t; + init = build (MODIFY_EXPR, TREE_TYPE (nvtbl), + nvtbl, vtbl); + TREE_SIDE_EFFECTS (init) = 1; + expand_expr_stmt (init); + /* Update the vtable pointers as necessary. */ + ref = build_vfield_ref (build_indirect_ref (addr, NULL_PTR), DECL_CONTEXT (CLASSTYPE_VFIELD (BINFO_TYPE (binfo)))); + expand_expr_stmt (build_modify_expr (ref, NOP_EXPR, + build_unary_op (ADDR_EXPR, nvtbl, 0))); + } + assemble_external (vtbl); + aref = build_array_ref (vtbl, idx); + naref = build_array_ref (nvtbl, idx); + old_delta = build_component_ref (aref, delta_identifier, 0, 0); + new_delta = build_component_ref (naref, delta_identifier, 0, 0); + old_delta = build_binary_op (PLUS_EXPR, old_delta, + TREE_VALUE (delta), 0); + if (vc) + { + /* If this is set, we need to add in delta adjustments for + the other virtual base. */ + tree vc_delta = purpose_member (vc, *vbase_offsets); + if (! vc_delta) + { + tree vc_addr = convert_pointer_to_real (vc, orig_addr); + vc_delta = (tree)CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (vc)); + vc_delta = build (MINUS_EXPR, ptrdiff_type_node, + vc_addr, vc_delta); + vc_delta = save_expr (vc_delta); + *vbase_offsets = tree_cons (vc, vc_delta, *vbase_offsets); + } + else + vc_delta = TREE_VALUE (vc_delta); + + old_delta = build_binary_op (PLUS_EXPR, old_delta, vc_delta, 0); + } + + TREE_READONLY (new_delta) = 0; + 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, addr, orig_addr, type, vbase, *vbase_offsets; + int init_self, can_elide; +{ + 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))) + { + addr = convert_pointer_to_real (binfo, addr); + expand_upcast_fixups (real_binfo, addr, orig_addr, vbase, 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 @@ -2494,7 +2814,7 @@ init_vbase_pointers (type, decl_ptr) are initializing. When USE_COMPUTED_OFFSETS is non-zero, we can assume that the - object was laidout by a top-level contructor and the computed + 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. @@ -2510,6 +2830,7 @@ expand_indirect_vtbls_init (binfo, true_ tree type = BINFO_TYPE (binfo); if (TYPE_USES_VIRTUAL_BASECLASSES (type)) { + rtx fixup_insns = NULL_RTX; int old_flag = flag_this_is_variable; tree vbases = CLASSTYPE_VBASECLASSES (type); vbase_types = vbases; @@ -2520,9 +2841,10 @@ expand_indirect_vtbls_init (binfo, true_ { /* This is an object of type IN_TYPE, */ flag_this_is_variable = -2; - dfs_walk (binfo, dfs_find_vbases, unmarked_new_vtablep); } + dfs_walk (binfo, dfs_find_vbases, unmarked_new_vtablep); + /* Initialized with vtables of type TYPE. */ for (; vbases; vbases = TREE_CHAIN (vbases)) { @@ -2531,6 +2853,10 @@ expand_indirect_vtbls_init (binfo, true_ addr = (tree)CLASSTYPE_SEARCH_SLOT (BINFO_TYPE (vbases)); else { +#if 1 + addr = convert_pointer_to_vbase (TREE_TYPE (vbases), vbase_decl_ptr); +#else + /* This should should never work better than the above. (mrs) */ tree vbinfo = get_binfo (TREE_TYPE (vbases), TREE_TYPE (vbase_decl), 0); @@ -2553,6 +2879,7 @@ expand_indirect_vtbls_init (binfo, true_ if (addr == error_mark_node) continue; } +#endif } /* Do all vtables from this virtual base. */ @@ -2560,6 +2887,46 @@ expand_indirect_vtbls_init (binfo, true_ binfos. (in the CLASSTPE_VFIELD_PARENT sense) */ expand_direct_vtbls_init (vbases, TYPE_BINFO (BINFO_TYPE (vbases)), 1, 0, addr); + + /* If we are using computed offsets we can skip fixups. */ + if (use_computed_offsets) + continue; + + /* Now we adjust the offsets for virtual functions that cross + virtual boundaries on an implicit upcast on vf call so that + the layout of the most complete type is used, instead of + assuming the layout of the virtual bases from our current type. */ + + 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); @@ -2724,13 +3091,107 @@ note_debug_info_needed (type) /* 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; + + /* 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 = (TREE_CODE (value) == FUNCTION_DECL + && DECL_VIRTUAL_P (value)) + ? DECL_CLASS_CONTEXT (value) + : DECL_CONTEXT (value); + + if (context == type) + { + if (TREE_CODE (value) == TYPE_DECL + && DECL_ARTIFICIAL (value)) + *values = NULL_TREE; + else + dont_add = 1; + } + else if (context && TYPE_DERIVES_FROM (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 (context && TYPE_DERIVES_FROM (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; + } + } +} + /* Add the instance variables which this class contributed to the - current class binding contour. When a redefinition occurs, - if the redefinition is strictly within a single inheritance path, - we just overwrite (in the case of a data field) or - cons (in the case of a member function) the old declaration with - the new. If the fields are not within a single inheritance path, - we must cons them in either case. + 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", @@ -2769,117 +3230,25 @@ dfs_pushdecls (binfo) continue; } -#if 0 - if (TREE_CODE (fields) != TYPE_DECL) - { - DECL_PUBLIC (fields) = 0; - DECL_PROTECTED (fields) = 0; - DECL_PRIVATE (fields) = 0; - } -#endif - if (DECL_NAME (fields)) { - tree class_value = IDENTIFIER_CLASS_VALUE (DECL_NAME (fields)); - - /* If the class value is an envelope of the kind described in - the comment above, we try to rule out possible ambiguities. - If we can't do that, keep a TREE_LIST with possibly ambiguous - decls in there. */ - if (class_value && TREE_CODE (class_value) == TREE_LIST - && TREE_PURPOSE (class_value) != NULL_TREE - && (TREE_CODE (TREE_PURPOSE (class_value)) - != IDENTIFIER_NODE)) - { - tree value = TREE_PURPOSE (class_value); - tree context; - - /* Possible ambiguity. If its defining type(s) - is (are all) derived from us, no problem. */ - if (TREE_CODE (value) != TREE_LIST) - { - context = (TREE_CODE (value) == FUNCTION_DECL - && DECL_VIRTUAL_P (value)) - ? DECL_CLASS_CONTEXT (value) - : DECL_CONTEXT (value); - - if (context && (context == type - || TYPE_DERIVES_FROM (context, type))) - value = fields; - else - value = tree_cons (NULL_TREE, fields, - build_tree_list (NULL_TREE, value)); - } - else - { - /* All children may derive from us, in which case - there is no problem. Otherwise, we have to - keep lists around of what the ambiguities might be. */ - tree values; - int problem = 0; - - for (values = value; values; values = TREE_CHAIN (values)) - { - tree sub_values = TREE_VALUE (values); - - if (TREE_CODE (sub_values) == TREE_LIST) - { - for (; sub_values; sub_values = TREE_CHAIN (sub_values)) - { - register tree list_mbr = TREE_VALUE (sub_values); - - context = (TREE_CODE (list_mbr) == FUNCTION_DECL - && DECL_VIRTUAL_P (list_mbr)) - ? DECL_CLASS_CONTEXT (list_mbr) - : DECL_CONTEXT (list_mbr); - - if (! TYPE_DERIVES_FROM (context, type)) - { - value = tree_cons (NULL_TREE, TREE_VALUE (values), value); - problem = 1; - break; - } - } - } - else - { - context = (TREE_CODE (sub_values) == FUNCTION_DECL - && DECL_VIRTUAL_P (sub_values)) - ? DECL_CLASS_CONTEXT (sub_values) - : DECL_CONTEXT (sub_values); - - if (context && ! TYPE_DERIVES_FROM (context, type)) - { - value = tree_cons (NULL_TREE, values, value); - problem = 1; - break; - } - } - } - if (! problem) value = fields; - } - - /* Mark this as a potentially ambiguous member. */ - if (TREE_CODE (value) == TREE_LIST) - { - /* Leaving TREE_TYPE blank is intentional. - We cannot use `error_mark_node' (lookup_name) - or `unknown_type_node' (all member functions use this). */ - TREE_NONLOCAL_FLAG (value) = 1; - } + tree name = DECL_NAME (fields); + tree class_value = IDENTIFIER_CLASS_VALUE (name); - /* Put the new contents in our envelope. */ - TREE_PURPOSE (class_value) = value; - } - else + /* 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. */ - tree envelope = tree_cons (fields, class_value, - closed_envelopes); - - closed_envelopes = envelope; - IDENTIFIER_CLASS_VALUE (DECL_NAME (fields)) = envelope; + 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)); } } @@ -2890,78 +3259,32 @@ dfs_pushdecls (binfo) methods = &TREE_VEC_ELT (method_vec, 1); end = TREE_VEC_END (method_vec); - /* This does not work for multiple inheritance yet. */ while (methods != end) { /* This will cause lookup_name to return a pointer - to the tree_list of possible methods of this name. - If the order is a problem, we can nreverse them. */ - tree tmp; - tree class_value = IDENTIFIER_CLASS_VALUE (DECL_NAME (*methods)); - - if (class_value && TREE_CODE (class_value) == TREE_LIST - && TREE_PURPOSE (class_value) != NULL_TREE - && TREE_CODE (TREE_PURPOSE (class_value)) != IDENTIFIER_NODE) - { - tree old = TREE_PURPOSE (class_value); - - maybe_push_cache_obstack (); - if (TREE_CODE (old) == TREE_LIST) - tmp = tree_cons (DECL_NAME (*methods), *methods, old); - else - { - /* Only complain if we shadow something we can access. */ - if (old - && warn_shadow - && ((DECL_LANG_SPECIFIC (old) - && DECL_CLASS_CONTEXT (old) == current_class_type) - || ! TREE_PRIVATE (old))) - /* Should figure out access control more accurately. */ - { - cp_warning_at ("member `%#D' is shadowed", old); - cp_warning_at ("by member function `%#D'", *methods); - warning ("in this context"); - } - tmp = build_tree_list (DECL_NAME (*methods), *methods); - } - pop_obstacks (); - - TREE_TYPE (tmp) = unknown_type_node; -#if 0 - TREE_OVERLOADED (tmp) = DECL_OVERLOADED (*methods); -#endif - TREE_NONLOCAL_FLAG (tmp) = 1; - - /* Put the new contents in our envelope. */ - TREE_PURPOSE (class_value) = tmp; - } - else + to the tree_list of possible methods of this name. */ + tree name = DECL_NAME (*methods); + 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. */ + 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) { - maybe_push_cache_obstack (); - tmp = build_tree_list (DECL_NAME (*methods), *methods); - pop_obstacks (); - - TREE_TYPE (tmp) = unknown_type_node; -#if 0 - TREE_OVERLOADED (tmp) = DECL_OVERLOADED (*methods); -#endif - TREE_NONLOCAL_FLAG (tmp) = 1; - /* See comment above for a description of envelopes. */ - closed_envelopes = tree_cons (tmp, class_value, + closed_envelopes = tree_cons (NULL_TREE, class_value, closed_envelopes); - IDENTIFIER_CLASS_VALUE (DECL_NAME (*methods)) = closed_envelopes; - } -#if 0 - tmp = *methods; - while (tmp != 0) - { - DECL_PUBLIC (tmp) = 0; - DECL_PROTECTED (tmp) = 0; - DECL_PRIVATE (tmp) = 0; - tmp = DECL_CHAIN (tmp); + IDENTIFIER_CLASS_VALUE (name) = closed_envelopes; + class_value = IDENTIFIER_CLASS_VALUE (name); } -#endif + + /* Here we try to rule out possible ambiguities. + If we can't do that, keep a TREE_LIST with possibly ambiguous + decls in there. */ + maybe_push_cache_obstack (); + envelope_add_decl (type, *methods, &TREE_PURPOSE (class_value)); + pop_obstacks (); methods++; } @@ -3019,41 +3342,6 @@ push_class_decls (type) tree id; struct obstack *ambient_obstack = current_obstack; -#if 0 - tree tags = CLASSTYPE_TAGS (type); - - while (tags) - { - tree code_type_node; - tree tag; - - switch (TREE_CODE (TREE_VALUE (tags))) - { - case ENUMERAL_TYPE: - code_type_node = enum_type_node; - break; - case RECORD_TYPE: - code_type_node = record_type_node; - break; - case CLASS_TYPE: - code_type_node = class_type_node; - break; - case UNION_TYPE: - code_type_node = union_type_node; - break; - default: - my_friendly_abort (297); - } - tag = xref_tag (code_type_node, TREE_PURPOSE (tags), - TYPE_BINFO_BASETYPE (TREE_VALUE (tags), 0), 0); -#if 0 /* not yet, should get fixed properly later */ - pushdecl (make_type_decl (TREE_PURPOSE (tags), TREE_VALUE (tags))); -#else - pushdecl (build_decl (TYPE_DECL, TREE_PURPOSE (tags), TREE_VALUE (tags))); -#endif - } -#endif - search_stack = push_search_level (search_stack, &search_obstack); id = TYPE_IDENTIFIER (type); @@ -3213,3 +3501,24 @@ reinit_search_statistics () n_outer_fields_searched = 0; n_contexts_saved = 0; } + +static tree conversions; +static void +add_conversions (binfo) + tree binfo; +{ + tree tmp = CLASSTYPE_FIRST_CONVERSION (BINFO_TYPE (binfo)); + for (; tmp && IDENTIFIER_TYPENAME_P (DECL_NAME (tmp)); + tmp = TREE_CHAIN (tmp)) + conversions = tree_cons (DECL_NAME (tmp), TREE_TYPE (TREE_TYPE (tmp)), + conversions); +} + +tree +lookup_conversions (type) + tree type; +{ + conversions = NULL_TREE; + dfs_walk (TYPE_BINFO (type), add_conversions, 0); + return conversions; +}