diff options
author | obrien <obrien@FreeBSD.org> | 2000-05-27 02:25:28 +0000 |
---|---|---|
committer | obrien <obrien@FreeBSD.org> | 2000-05-27 02:25:28 +0000 |
commit | 2213994dde95f9976af97c2acabf8054049ba10a (patch) | |
tree | 09cae866f233ee92af84c7755922738bde568ea5 /contrib/gcc/cp | |
parent | ea11d3cf1c7ee988db5b61368d225c6f4f943335 (diff) | |
parent | 890b30850f08010e6461f2af573cb7b53a82ef36 (diff) | |
download | FreeBSD-src-2213994dde95f9976af97c2acabf8054049ba10a.zip FreeBSD-src-2213994dde95f9976af97c2acabf8054049ba10a.tar.gz |
This commit was generated by cvs2svn to compensate for changes in r60967,
which included commits to RCS files with non-trunk default branches.
Diffstat (limited to 'contrib/gcc/cp')
-rw-r--r-- | contrib/gcc/cp/ChangeLog | 114 | ||||
-rw-r--r-- | contrib/gcc/cp/call.c | 51 | ||||
-rw-r--r-- | contrib/gcc/cp/class.c | 354 | ||||
-rw-r--r-- | contrib/gcc/cp/cp-tree.h | 72 | ||||
-rw-r--r-- | contrib/gcc/cp/decl2.c | 95 | ||||
-rw-r--r-- | contrib/gcc/cp/exception.cc | 4 | ||||
-rw-r--r-- | contrib/gcc/cp/init.c | 234 | ||||
-rw-r--r-- | contrib/gcc/cp/method.c | 221 | ||||
-rw-r--r-- | contrib/gcc/cp/pt.c | 38 | ||||
-rw-r--r-- | contrib/gcc/cp/rtti.c | 25 | ||||
-rw-r--r-- | contrib/gcc/cp/search.c | 120 |
11 files changed, 1265 insertions, 63 deletions
diff --git a/contrib/gcc/cp/ChangeLog b/contrib/gcc/cp/ChangeLog index 309d8e2..3f00533 100644 --- a/contrib/gcc/cp/ChangeLog +++ b/contrib/gcc/cp/ChangeLog @@ -1,3 +1,117 @@ +2000-03-08 Nathan Sidwell <nathan@codesourcery.com> + + * exception.cc (__cp_pop_exception): Cleanup the original object. + +1999-11-13 Jason Merrill <jason@yorick.cygnus.com> + + * rtti.c (get_tinfo_fn_unused): Split out from get_tinfo_fn. + * class.c (set_rtti_entry): Use it. + +Wed Apr 12 00:45:49 2000 Jeffrey A Law (law@cygnus.com) + + 2000-02-03 <loewis@informatik.hu-berlin.de> + * call.c (add_function_candidate): Do not add vlist ctor into + candidates in compatibility mode. + (build_user_type_conversion_1): Add LOOKUP_HAS_VLIST when adding + vlist. + (convert_like): Likewise. + (build_over_call): Skip vlist only if it is mentioned in flags. + (build_new_method_call): Do not add vlist in compatibility mode, + except for dtors. + * cp-tree.h (flag_vtable_thunks): Has now four possible values. + (DECL_VLIST_CTOR_WRAPPER_P, DECL_VLIST_CTOR_WRAPPED): New macros. + (in_charge_identifier): Declare external. + * decl.c (xref_basetypes): Check for vtable_thunks >=2. + (finish_dtor): Use bit 2 of in_chrg. + (finish_function): Do not finish vlist ctor wrappers. + * decl2.c (flag_vtable_thunks_compat): New variable. + (lang_decode_option): Set it accordingly. + (maybe_retrofit_in_chrg): Call make_vlist_ctor_wrapper. + * init.c (build_base_dtor_call): Pass 4 in in_chrg. + (no_vlist_base_init): New function. + (expand_default_init): Do not pass vlist in compatibility mode. + Try to call old base ctor if new one was not generated. + (build_new_1): Do not pass vlist in compatibility mode. + * method.c (get_id_2): Do not put _Vlist into dtor name in + compatibility mode. + (make_vlist_ctor_wrapper, emit_vlist_ctor_wrapper): New functions. + (synthesize_method): Call emit_vlist_ctor_wrapper. + * pt.c (instantiate_class_template): Check for vtable_thunks >=2. + + Sat Nov 13 15:48:59 1999 H.J. Lu <hjl@gnu.org> + * init.c (finish_dtor): Call mark_all_temps_used () before + declaring vlist. + + Tue Nov 9 15:01:57 1999 H.J. Lu <hjl@gnu.org> + * init.c (construct_virtual_bases): Update. + (expand_cleanup_for_base): Update. + + Tue Nov 9 08:25:04 1999 H.J. Lu <hjl@gnu.org> + * init.c (construct_virtual_bases): Update. + (expand_cleanup_for_base): Take vlist parameter. + (emit_base_init): Pass vlist to expand_cleanup_for_base. + (construct_virtual_bases): Likewise. + + 1999-05-02 Martin von Löwis <loewis@informatik.hu-berlin.de> + * class.c (prepare_ctor_vtable, finish_one_ctor_vtable, + prepend_ctor_vfields_for_vbase, finish_ctor_vtables_for_vbases, + finish_ctor_vtables_1, prepend_vbase_vfields, + finish_ctor_vtables): New functions. + (finish_struct_1): Call finish_ctor_vtables. + * cp-tree.h (TYPE_USES_PVBASES): New macro. + (constructor_for_vbase_attr): Widen to two bits. + (CONSTRUCTOR_FOR_VBASE, CONSTRUCTOR_FOR_PVBASE, + DESTRUCTOR_FOR_PVBASE): New macros. + (DECL_CONSTRUCTOR_FOR_VBASE_P): Adopt to new enumeration. + (DECL_CONSTRUCTOR_FOR_VBASE): New macro. + (DECL_CONSTRUCTOR_FOR_PVBASE_P, DECL_DESTRUCTOR_FOR_PVBASE_P): New + macros. + (vlist_identifier, vlist_type_node, vlist_zero_node): Declare. + (VCTABLE_NAME, VLIST_NAME_FORMAT, VLIST_NAME, VLIST1_NAME, + VLIST_TYPE_NAME): New macros. + (LOOKUP_HAS_VLIST): New macro. + (build_base_dtor_call, init_vlist): Declare. + (build_destructor_name): Add int argument. + * decl.c (vlist_identifier, vlist_type_node, vlist_zero_node): + Define. + (init_decl_processing): Initialize them. + (grokdeclarator): Handle vlist argument. + (copy_args_p): Likewise. + (grok_ctor_properties): Don't try to skip initial int for + templates. Skip vlist if available. + (xref_basetypes): Set TYPE_USES_PVBASES. + (finish_dtor, finish_ctor): New functions, moved out of ... + (finish_function): ... here. + * decl2.c (lang_decode_option): Set flag_vtable_thunks explicitly. + (maybe_retrofit_in_chrg): Retrofit __vlist parameter. + (grokclassfn): Pass pvbase flag into mangled name. + * init.c (build_base_dtor_call): New function. + (build_partial_cleanup_for): Call it. + (pvbasecount, init_vlist, ): New functions. + (emit_base_init): Process vlist argument. + (expand_aggr_vbase_init_1): Likewise. + (expand_aggr_vbase_init): Likewise. + (expand_default_init): Likewise. + (build_new_1): Pass null vlist argument. + (build_delete): Likewise. Call build_base_dtor_call. + * method.c (process_overload_item): Mangle _Vlist specially. + (build_base_path, get_vlist_vtable_id): New functions. + (build_destructor_name): Potentially mangle _Vlist into it. + (do_build_copy_constructor): Skip vlist argument. + (synthesize_method): Likewise. + * pt.c (has_pvbases_p): New function. + (instantiate_class_template): Call it. + (tsubst_decl): Retrofit before mangling. Pass pvbase_p to + destructor mangling. + * search.c (expand_direct_vtbls_init_thunks): New function. + (expand_indirect_vtbls_init_thunks): New function. + (expand_indirect_vtbls_init): Call it. + * call.c (add_function_candidate): Process vlist argument. + (build_user_type_conversion_1): Add vlist argument. + (convert_like): Likewise. + (build_over_call): Likewise. + (build_new_method_call): Likewise. + 2000-02-18 Martin von Loewis <loewis@informatik.hu-berlin.de> * typeck2.c (my_friendly_abort): Use GCCBUGURL. diff --git a/contrib/gcc/cp/call.c b/contrib/gcc/cp/call.c index 094a345..a931500 100644 --- a/contrib/gcc/cp/call.c +++ b/contrib/gcc/cp/call.c @@ -1065,8 +1065,8 @@ add_function_candidate (candidates, fn, arglist, flags) tree parmnode, argnode; int viable = 1; - /* The `this' and `in_chrg' arguments to constructors are not considered - in overload resolution. */ + /* The `this', `in_chrg', and `vlist' arguments to constructors are + not considered in overload resolution. */ if (DECL_CONSTRUCTOR_P (fn)) { parmlist = TREE_CHAIN (parmlist); @@ -1076,6 +1076,22 @@ add_function_candidate (candidates, fn, arglist, flags) parmlist = TREE_CHAIN (parmlist); arglist = TREE_CHAIN (arglist); } + if ((flags & LOOKUP_HAS_VLIST) + && DECL_CONSTRUCTOR_FOR_PVBASE_P (fn)) + { + parmlist = TREE_CHAIN (parmlist); + arglist = TREE_CHAIN (arglist); + } + else if (!(flags & LOOKUP_HAS_VLIST) + && !DECL_CONSTRUCTOR_FOR_PVBASE_P (fn)) + /* Ok */; + else + { + /* The ctor expects a vlist and the arguments don't have + one, or vice versa, so fn is not even a candidate, since + the corresponding ctor would be the candidate. */ + return candidates; + } } len = list_length (arglist); @@ -2071,6 +2087,11 @@ build_user_type_conversion_1 (totype, expr, flags) tree t = build_int_2 (0, 0); TREE_TYPE (t) = build_pointer_type (totype); args = build_scratch_list (NULL_TREE, expr); + if (TYPE_USES_PVBASES (totype) && !flag_vtable_thunks_compat) + { + args = scratch_tree_cons (NULL_TREE, vlist_zero_node, args); + flags |= LOOKUP_HAS_VLIST; + } if (TYPE_USES_VIRTUAL_BASECLASSES (totype)) args = scratch_tree_cons (NULL_TREE, integer_one_node, args); args = scratch_tree_cons (NULL_TREE, t, args); @@ -3038,6 +3059,7 @@ convert_like (convs, expr) = WRAPPER_PTR (TREE_OPERAND (convs, 1)); tree fn = cand->fn; tree args; + int flags = LOOKUP_NORMAL; if (DECL_CONSTRUCTOR_P (fn)) { @@ -3045,13 +3067,19 @@ convert_like (convs, expr) TREE_TYPE (t) = build_pointer_type (DECL_CONTEXT (fn)); args = build_scratch_list (NULL_TREE, expr); + if (TYPE_USES_PVBASES (DECL_CONTEXT (fn)) + && !flag_vtable_thunks_compat) + { + args = scratch_tree_cons (NULL_TREE, vlist_zero_node, args); + flags != LOOKUP_HAS_VLIST; + } if (TYPE_USES_VIRTUAL_BASECLASSES (DECL_CONTEXT (fn))) args = scratch_tree_cons (NULL_TREE, integer_one_node, args); args = scratch_tree_cons (NULL_TREE, t, args); } else args = build_this (expr); - expr = build_over_call (cand, args, LOOKUP_NORMAL); + expr = build_over_call (cand, args, flags); /* If this is a constructor or a function returning an aggr type, we need to build up a TARGET_EXPR. */ @@ -3260,6 +3288,13 @@ build_over_call (cand, args, flags) arg = TREE_CHAIN (arg); parm = TREE_CHAIN (parm); } + if (flags & LOOKUP_HAS_VLIST) + { + converted_args = expr_tree_cons + (NULL_TREE, TREE_VALUE (arg), converted_args); + arg = TREE_CHAIN (arg); + parm = TREE_CHAIN (parm); + } } /* Bypass access control for 'this' parameter. */ else if (TREE_CODE (TREE_TYPE (fn)) == METHOD_TYPE) @@ -3369,6 +3404,8 @@ build_over_call (cand, args, flags) arg = TREE_CHAIN (converted_args); if (TYPE_USES_VIRTUAL_BASECLASSES (DECL_CONTEXT (fn))) arg = TREE_CHAIN (arg); + if (flags & LOOKUP_HAS_VLIST) + arg = TREE_CHAIN (arg); arg = TREE_VALUE (arg); /* Pull out the real argument, disregarding const-correctness. */ @@ -3544,6 +3581,8 @@ build_new_method_call (instance, name, args, basetype_path, flags) remove it for error reporting. */ if (flags & LOOKUP_HAS_IN_CHARGE) user_args = TREE_CHAIN (args); + if (flags & LOOKUP_HAS_VLIST) + user_args = TREE_CHAIN (user_args); args = resolve_args (args); @@ -3616,6 +3655,12 @@ build_new_method_call (instance, name, args, basetype_path, flags) if (name == ctor_identifier && TYPE_USES_VIRTUAL_BASECLASSES (basetype) && ! (flags & LOOKUP_HAS_IN_CHARGE)) { + if (TYPE_USES_PVBASES(basetype) + && (!flag_vtable_thunks_compat || (name == dtor_identifier))) + { + args = scratch_tree_cons (NULL_TREE, vlist_zero_node, args); + flags |= LOOKUP_HAS_VLIST; + } flags |= LOOKUP_HAS_IN_CHARGE; args = scratch_tree_cons (NULL_TREE, integer_one_node, args); } diff --git a/contrib/gcc/cp/class.c b/contrib/gcc/cp/class.c index 400c67d..74808c5 100644 --- a/contrib/gcc/cp/class.c +++ b/contrib/gcc/cp/class.c @@ -102,8 +102,15 @@ static tree get_basefndecls PROTO((tree, tree)); static void set_rtti_entry PROTO((tree, tree, tree)); static tree build_vtable PROTO((tree, tree)); static void prepare_fresh_vtable PROTO((tree, tree)); +static tree prepare_ctor_vtable PROTO((tree, tree, tree)); static void fixup_vtable_deltas1 PROTO((tree, tree)); static void fixup_vtable_deltas PROTO((tree, int, tree)); +static tree finish_one_ctor_vtable PROTO((tree, tree, tree, tree)); +static tree prepend_ctor_vfields_for_vbase PROTO((tree, tree, tree, tree, int, tree)); +static tree finish_ctor_vtables_for_vbases PROTO((tree, tree, tree)); +static tree finish_ctor_vtables_1 PROTO((tree, tree)); +static tree prepend_vbase_vfields PROTO((tree, int, tree)); +static void finish_ctor_vtables PROTO((tree)); static void finish_vtbls PROTO((tree, int, tree)); static void modify_vtable_entry PROTO((tree, tree, tree)); static tree get_vtable_entry_n PROTO((tree, unsigned HOST_WIDE_INT)); @@ -673,7 +680,7 @@ set_rtti_entry (virtuals, offset, type) return; if (flag_rtti) - vfn = build1 (ADDR_EXPR, vfunc_ptr_type_node, get_tinfo_fn (type)); + vfn = build1 (ADDR_EXPR, vfunc_ptr_type_node, get_tinfo_fn_unused (type)); else vfn = build1 (NOP_EXPR, vfunc_ptr_type_node, size_zero_node); TREE_CONSTANT (vfn) = 1; @@ -922,6 +929,43 @@ prepare_fresh_vtable (binfo, for_type) SET_BINFO_NEW_VTABLE_MARKED (binfo); } +/* Return a new vtable for use in initialization of the BASE subobject + of COMPLETE_TYPE. The vtable there goes into the vfield of the + VBASEBASE virtual subobject. */ + +static tree +prepare_ctor_vtable (complete_type, base, vbasebase) + tree complete_type, base, vbasebase; +{ + tree orig_decl = BINFO_VTABLE (vbasebase); + tree name = get_vlist_vtable_id (base, vbasebase); + tree new_decl; + + new_decl = build_lang_decl (VAR_DECL, name, TREE_TYPE (orig_decl)); + /* Remember which class this vtable is really for. */ + DECL_CONTEXT (new_decl) = complete_type; + + DECL_ARTIFICIAL (new_decl) = 1; + TREE_STATIC (new_decl) = 1; + new_decl = pushdecl_top_level (new_decl); + DECL_VIRTUAL_P (new_decl) = 1; +#ifndef WRITABLE_VTABLES + /* Make them READONLY by default. (mrs) */ + TREE_READONLY (new_decl) = 1; +#endif + DECL_ALIGN (new_decl) = DECL_ALIGN (orig_decl); + +#ifdef GATHER_STATISTICS + n_vtables += 1; + n_vtable_elems += list_length (BINFO_VIRTUALS (binfo)); +#endif + + /* Set TREE_PUBLIC and TREE_EXTERN as appropriate. */ + import_export_vtable (new_decl, complete_type, 0); + + return new_decl; +} + #if 0 /* Access the virtual function table entry that logically contains BASE_FNDECL. VIRTUALS is the virtual function table's @@ -1798,6 +1842,7 @@ finish_struct_bits (t, max_has_virtual) TYPE_USES_COMPLEX_INHERITANCE (variants) = TYPE_USES_COMPLEX_INHERITANCE (t); TYPE_VIRTUAL_P (variants) = TYPE_VIRTUAL_P (t); TYPE_USES_VIRTUAL_BASECLASSES (variants) = TYPE_USES_VIRTUAL_BASECLASSES (t); + TYPE_USES_PVBASES (variants) = TYPE_USES_PVBASES (t); /* Copy whatever these are holding today. */ TYPE_MIN_VALUE (variants) = TYPE_MIN_VALUE (t); TYPE_MAX_VALUE (variants) = TYPE_MAX_VALUE (t); @@ -2933,6 +2978,309 @@ warn_hidden (t) } } +/* Generate one vtable for use in constructors or destructors of BASE + subobjects of COMPLETE_TYPE objects. The vtable belongs to the + vfield of the VBASEVASE subobject of the VBASE virtual base of + COMPLETE_TYPE (and BASE). */ + +static tree +finish_one_ctor_vtable (complete_type, base, vbase, vbasebase) + tree complete_type, base, vbase, vbasebase; +{ + tree virtuals; + tree newtable; + tree newvirtuals; + tree offset; + tree newvbase = binfo_member (BINFO_TYPE (vbase), + CLASSTYPE_VBASECLASSES (complete_type)); + + newtable = prepare_ctor_vtable (complete_type, base, vbasebase); + newvirtuals = copy_list (BINFO_VIRTUALS (vbasebase)); + + virtuals = newvirtuals; + /* Change the offset entry. First, delta between base an vbase. */ + offset = ssize_binop (MINUS_EXPR, BINFO_OFFSET (newvbase), + BINFO_OFFSET (base)); + /* Add delta between vbase and vbasebase. */ + offset = ssize_binop (PLUS_EXPR, offset, BINFO_OFFSET (vbasebase)); + offset = ssize_binop (MINUS_EXPR, offset, BINFO_OFFSET (vbase)); + /* Finally, negate. */ + offset = ssize_binop (MINUS_EXPR, integer_zero_node, offset); + offset = build1 (NOP_EXPR, vfunc_ptr_type_node, offset); + TREE_CONSTANT (offset) = 1; + TREE_VALUE (virtuals) = build_vtable_entry (integer_zero_node, offset); + virtuals = TREE_CHAIN (virtuals); + + /* Skip the typeinfo function. */ + virtuals = TREE_CHAIN (virtuals); + + /* Iterate over all methods of this virtual base. */ + for (; virtuals; virtuals = TREE_CHAIN (virtuals)) + { + tree fndecl = TREE_VALUE (virtuals); + tree pfn = FNADDR_FROM_VTABLE_ENTRY (fndecl); + fndecl = TREE_OPERAND (pfn, 0); + if (fndecl) + { + tree delta, newdelta, binfo_context; + tree context = DECL_CLASS_CONTEXT (fndecl); + + /* If this method is implemented in a base of the vbase, the + thunk we have is correct. */ + if (DERIVED_FROM_P (context, vbase)) + continue; + + binfo_context = binfo_value (context, base); + if (TREE_VIA_VIRTUAL (binfo_context)) + binfo_context = binfo_member + (context, CLASSTYPE_VBASECLASSES (complete_type)); + /* This is the delta from a complete C to a B subobject, or + more generally to the base subobject that implements the + virtual function for B. BASE already has the offset to + the complete type. */ + delta = BINFO_OFFSET (binfo_context); + /* This is the delta from the A to the complete C. */ + newdelta = BINFO_OFFSET (newvbase); + /* This is the delta from the A to the B subobject. */ + newdelta = size_binop (MINUS_EXPR, newdelta, delta); + newdelta = ssize_binop (MINUS_EXPR, integer_zero_node, + newdelta); + + modify_vtable_entry (virtuals, + build_vtable_entry (newdelta, pfn), + fndecl); + } + } + DECL_INITIAL (newtable) = build_nt (CONSTRUCTOR, NULL_TREE, + newvirtuals); + DECL_CONTEXT (newtable) = NULL_TREE; + cp_finish_decl (newtable, DECL_INITIAL (newtable), NULL_TREE, 0, 0); + DECL_CONTEXT (newtable) = complete_type; + return newtable; +} + +/* Add all vtables into LIST for the VBASEBASE subobject and its bases + of VBASE virtual BASE of COMPLETE_TYPE for use in BASE + constructors. DO_SELF indicates whether this is the VBASEBASE that + has 'primary' vfield. Return the new LIST. */ + +static tree +prepend_ctor_vfields_for_vbase (complete_type, base, vbase, vbasebase, + do_self, list) + tree complete_type, base, vbase, vbasebase; + int do_self; + tree list; +{ + int i; + tree vtbl; + tree bases = BINFO_BASETYPES (vbasebase); + int vfp = CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (vbasebase)); + + if (do_self && CLASSTYPE_VFIELDS (BINFO_TYPE (vbasebase))) + { + vtbl = finish_one_ctor_vtable (complete_type, base, vbase, vbasebase); + vtbl = build1 (ADDR_EXPR, vtbl_ptr_type_node, vtbl); + TREE_READONLY (vtbl) = 1; + TREE_CONSTANT (vtbl) = 1; + list = tree_cons (NULL_TREE, vtbl, list); + } + + if (!bases) + return list; + + for (i = 0; i < TREE_VEC_LENGTH (bases); i++) + { + tree vbasebase = TREE_VEC_ELT (bases, i); + if (TREE_VIA_VIRTUAL (vbasebase)) + continue; + list = prepend_ctor_vfields_for_vbase + (complete_type, base, vbase, vbasebase, (i != vfp), list); + } + + return list; +} + +/* Iterate over all virtual bases of the BASE subobject of + COMPLETE_TYPE. This list is given in VBASES. Return the list of + vtables generated in the process. */ + +static tree +finish_ctor_vtables_for_vbases (vbases, base, complete_type) + tree vbases, base, complete_type; +{ + tree result = NULL_TREE; + + for (; vbases; vbases = TREE_CHAIN (vbases)) + result = prepend_ctor_vfields_for_vbase + (complete_type, base, vbases, vbases, 1, result); + return result; +} + +/* Generate special vtables for virtual bases for use inside base + class ctors and dtors. Inside this function, we assume the + following scenario: + class A{virtual void foo();}; + class B:virtual A{int member1;} + class C:B{int member2;} + + BINFO is a base subject (e.g. B) of COMPLETE_TYPE. Returns the list + of virtual tables. */ + +static tree +finish_ctor_vtables_1 (binfo, complete_type) + tree binfo; + tree complete_type; +{ + int i; + tree binfos; + tree result = NULL_TREE; + + binfos = BINFO_BASETYPES (binfo); + if (!binfos) + return result; + + /* Iterate over all bases (i.e. B). */ + for (i = 0; i < TREE_VEC_LENGTH (binfos); i++) + { + tree base = TREE_VEC_ELT (binfos, i); + tree vbases = CLASSTYPE_VBASECLASSES (BINFO_TYPE (base)); + if (!vbases) + /* This base class does not have virtual bases. */ + continue; + if (TREE_VIA_VIRTUAL (base)) + /* A virtual base class is initialized on in the most-derived + constructor. */ + continue; + if (!TYPE_USES_PVBASES (BINFO_TYPE (base))) + /* Class has no polymorphic vbases. */ + continue; + /* Prepend vtable list for base class. */ + result = chainon (finish_ctor_vtables_1 (base, complete_type), + result); + /* Prepend our own vtable list. */ + result = chainon + (finish_ctor_vtables_for_vbases (vbases, base, complete_type), + result); + } + return result; +} + +/* Add the vtables of a virtual base BINFO in front of LIST, returning + the new list. DO_SELF indicates whether we have to return the + vtable of a vfield borrowed in a derived class. */ + +static tree +prepend_vbase_vfields (binfo, do_self, list) + tree binfo; + int do_self; + tree list; +{ + int i; + tree vtbl; + tree bases = BINFO_BASETYPES (binfo); + int vfp = CLASSTYPE_VFIELD_PARENT (BINFO_TYPE (binfo)); + + if (do_self && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo))) + { + vtbl = BINFO_VTABLE (binfo); + vtbl = build1 (ADDR_EXPR, vtbl_ptr_type_node, vtbl); + TREE_READONLY (vtbl) = 1; + TREE_CONSTANT (vtbl) = 1; + list = tree_cons (NULL_TREE, vtbl, list); + } + + if (!bases) + return list; + + for (i = 0; i < TREE_VEC_LENGTH (bases); i++) + { + tree base = TREE_VEC_ELT (bases, i); + if (TREE_VIA_VIRTUAL (base)) + continue; + list = prepend_vbase_vfields (base, (i != vfp), list); + } + + return list; +} + +/* Wrapper around finish_ctor_vtables_1. Compute the vtable list for + type T. */ + +static void +finish_ctor_vtables (t) + tree t; +{ + tree veclist = NULL_TREE; + tree decl, type; + char *name; + tree vbase; + int len; + + /* This is only good for vtable thunks. */ + my_friendly_assert (flag_vtable_thunks, 990307); + + /* Start with the list of most-derived vtables. */ + + for (vbase = CLASSTYPE_VBASECLASSES (t); vbase; + vbase = TREE_CHAIN (vbase)) + veclist = prepend_vbase_vfields (vbase, 1, veclist); + + /* Compute the list of vtables for the bases. */ + veclist = chainon (veclist, finish_ctor_vtables_1 (TYPE_BINFO (t), t)); + + /* Finally, we initialize the virtual bases first. */ + for (vbase = CLASSTYPE_VBASECLASSES (t); vbase; + vbase = TREE_CHAIN (vbase)) + { + tree vbases = CLASSTYPE_VBASECLASSES (BINFO_TYPE (vbase)); + if (!vbases) + continue; + veclist = chainon (veclist, + finish_ctor_vtables_for_vbases (vbases, vbase, t)); + veclist = chainon (veclist, + finish_ctor_vtables_1 (vbase, t)); + } + + veclist = nreverse (veclist); + + /* Generate the name for the vtable list. */ + name = alloca (strlen (VLIST_NAME_FORMAT) + + TYPE_ASSEMBLER_NAME_LENGTH (t) + 2); + sprintf (name, VLIST_NAME_FORMAT, TYPE_ASSEMBLER_NAME_STRING (t)); + + /* Build the type of the list. */ + len = list_length (veclist) - 1; + if (len < 0) + /* If this class has virtual bases without virtual methods, make a + single zero-entry in the array. This avoids zero-sized objects. */ + len++; + type = build_cplus_array_type (vtbl_ptr_type_node, + build_index_type (size_int (len))); + + + /* Produce a new decl holding the list. */ + decl = build_lang_decl (VAR_DECL, get_identifier (name), type); + TREE_STATIC (decl) = 1; + TREE_READONLY (decl) = 1; + decl = pushdecl_top_level (decl); + import_export_vtable (decl, t, 0); + DECL_INITIAL (decl) = build_nt (CONSTRUCTOR, NULL_TREE, veclist); + + DECL_ARTIFICIAL (decl) = 1; + /* This tells finish_file et.al. that this is related to virtual + tables. There is currently no way to distinguish between vtables + and vlists, other than the name of the decl. */ + DECL_VIRTUAL_P (decl) = 1; + + /* Output the array. */ + cp_finish_decl (decl, DECL_INITIAL (decl), NULL_TREE, 0, 0); + + /* Set the class context after finishing, so that finish thinks this + is an unrelated global, and then finish_vtable_vardecl knows what + class this is related to. */ + DECL_CONTEXT (decl) = t; +} + /* Check for things that are invalid. There are probably plenty of other things we should check for also. */ @@ -4069,6 +4417,10 @@ finish_struct_1 (t, warn_anon) /* Make the rtl for any new vtables we have created, and unmark the base types we marked. */ finish_vtbls (TYPE_BINFO (t), 1, t); + /* If we use thunks, and have virtual bases, we might need to emit + additional vtables. */ + if (flag_vtable_thunks && TYPE_USES_PVBASES (t)) + finish_ctor_vtables (t); hack_incomplete_structures (t); #if 0 diff --git a/contrib/gcc/cp/cp-tree.h b/contrib/gcc/cp/cp-tree.h index 7180915..8c1e7df 100644 --- a/contrib/gcc/cp/cp-tree.h +++ b/contrib/gcc/cp/cp-tree.h @@ -52,7 +52,7 @@ Boston, MA 02111-1307, USA. */ 4: BINFO_NEW_VTABLE_MARKED. TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR, or FIELD_DECL). - 5: Not used. + 5: TYPE_USES_PVBASES (in a class TYPE). 6: Not used. Usage of TYPE_LANG_FLAG_?: @@ -503,8 +503,9 @@ extern int write_virtuals; /* True for more efficient but incompatible (not fully tested) vtable implementation (using thunks). - 0 is old behavior; 1 is new behavior. */ -extern int flag_vtable_thunks; + 0 is old behavior; 1 is new behavior; 3 adds vlist arguments; + 2 is 3 plus backwards-compatibility to 1. */ +extern int flag_vtable_thunks, flag_vtable_thunks_compat; /* INTERFACE_ONLY nonzero means that we are in an "interface" section of the compiler. INTERFACE_UNKNOWN nonzero means @@ -889,6 +890,10 @@ struct lang_type hierarchy, then we can use more efficient search techniques. */ #define TYPE_USES_VIRTUAL_BASECLASSES(NODE) (TREE_LANG_FLAG_3(NODE)) +/* Nonzero means that this _CLASSTYPE uses polymorphic virtual bases. + This flag is set only when we use vtable thunks. */ +#define TYPE_USES_PVBASES(NODE) (TREE_LANG_FLAG_5(NODE)) + /* Vector member functions defined in this class. Each element is either a FUNCTION_DECL, a TEMPLATE_DECL, or an OVERLOAD. All functions with the same name end up in the same slot. The first @@ -965,7 +970,7 @@ struct lang_type /* The number of virtual functions defined for this _CLASSTYPE node. */ #define CLASSTYPE_VSIZE(NODE) (TYPE_LANG_SPECIFIC(NODE)->vsize) -/* The virtual base classes that this type uses. */ +/* The list of binfos of virtual base classes that this type uses. */ #define CLASSTYPE_VBASECLASSES(NODE) (TYPE_LANG_SPECIFIC(NODE)->vbases) /* The virtual function pointer fields that this type contains. */ #define CLASSTYPE_VFIELDS(NODE) (TYPE_LANG_SPECIFIC(NODE)->vfields) @@ -1165,22 +1170,21 @@ struct lang_decl_flags unsigned static_function : 1; unsigned const_memfunc : 1; unsigned volatile_memfunc : 1; - unsigned abstract_virtual : 1; unsigned permanent_attr : 1 ; - unsigned constructor_for_vbase_attr : 1; + unsigned mutable_flag : 1; unsigned is_default_implementation : 1; unsigned saved_inline : 1; unsigned use_template : 2; - unsigned nonconverting : 1; unsigned declared_inline : 1; unsigned not_really_extern : 1; unsigned needs_final_overrider : 1; unsigned bitfield : 1; unsigned defined_in_class : 1; - unsigned dummy : 4; + unsigned constructor_for_vbase_attr : 2; + unsigned dummy : 3; tree access; tree context; @@ -1226,9 +1230,35 @@ struct lang_decl #define DECL_CONV_FN_P(NODE) \ (IDENTIFIER_TYPENAME_P (DECL_NAME (NODE)) && TREE_TYPE (DECL_NAME (NODE))) -/* For FUNCTION_DECLs: nonzero means that this function is a constructor +#define CONSTRUCTOR_FOR_VBASE 1 +#define CONSTRUCTOR_FOR_PVBASE 2 +#define DESTRUCTOR_FOR_PVBASE 3 + +/* For FUNCTION_DECLs: nonzero means that this function is a con/destructor for an object with virtual baseclasses. */ -#define DECL_CONSTRUCTOR_FOR_VBASE_P(NODE) (DECL_LANG_SPECIFIC(NODE)->decl_flags.constructor_for_vbase_attr) +#define DECL_CONSTRUCTOR_FOR_VBASE(NODE) (DECL_LANG_SPECIFIC(NODE)->decl_flags.constructor_for_vbase_attr) + +/* Nonzero means that this function is a constructor for an object + with virtual baseclasses. */ +#define DECL_CONSTRUCTOR_FOR_VBASE_P(NODE) \ + (DECL_CONSTRUCTOR_FOR_VBASE (NODE) == CONSTRUCTOR_FOR_VBASE) + +/* Nonzero means that this function is a constructor for an object + with virtual baseclasses which have virtual functions. */ +#define DECL_CONSTRUCTOR_FOR_PVBASE_P(NODE) (DECL_LANG_SPECIFIC(NODE)->decl_flags.constructor_for_vbase_attr == CONSTRUCTOR_FOR_PVBASE) + +/* Nonzero means that this function is a destructor for an object + with virtual baseclasses which have virtual functions. */ +#define DECL_DESTRUCTOR_FOR_PVBASE_P(NODE) (DECL_LANG_SPECIFIC(NODE)->decl_flags.constructor_for_vbase_attr == DESTRUCTOR_FOR_PVBASE) + +/* Nonzero means that this function is a wrapper around a PVBASE ctor. */ +#define DECL_VLIST_CTOR_WRAPPER_P(NODE) \ + (DECL_CONSTRUCTOR_FOR_VBASE_P (NODE) && DECL_VLIST_CTOR_WRAPPED (NODE)\ + && TREE_CODE (DECL_VLIST_CTOR_WRAPPED (NODE)) == FUNCTION_DECL \ + && DECL_CONSTRUCTOR_FOR_PVBASE_P (DECL_VLIST_CTOR_WRAPPED (NODE))) + +/* Refers to original function that NODE wraps. */ +#define DECL_VLIST_CTOR_WRAPPED(NODE) DECL_MEMFUNC_POINTER_TO (NODE) /* Non-zero for a FUNCTION_DECL that declares a type-info function. */ #define DECL_TINFO_FN_P(NODE) \ @@ -2168,6 +2198,7 @@ extern tree delta2_identifier; extern tree pfn_or_delta2_identifier; extern tree tag_identifier; extern tree vt_off_identifier; +extern tree in_charge_identifier; /* A node that is a list (length 1) of error_mark_nodes. */ extern tree error_mark_list; @@ -2177,6 +2208,8 @@ extern tree class_type_node, record_type_node, union_type_node, enum_type_node; extern tree unknown_type_node; extern tree opaque_type_node, signature_type_node; +extern tree vlist_identifier, vlist_type_node, vlist_zero_node; + /* Node for "pointer to (virtual) function". This may be distinct from ptr_type_node so gdb can distinguish them. */ #define vfunc_ptr_type_node \ @@ -2292,6 +2325,8 @@ extern int current_function_parms_stored; #define AUTO_TEMP_FORMAT "_$tmp_%d" #define VTABLE_BASE "$vb" #define VTABLE_NAME_FORMAT (flag_vtable_thunks ? "__vt_%s" : "_vt$%s") +#define VCTABLE_NAME "__vc$" +#define VLIST_NAME_FORMAT "__vl$%s" #define VFIELD_BASE "$vf" #define VFIELD_NAME "_vptr$" #define VFIELD_NAME_FORMAT "_vptr$%s" @@ -2314,6 +2349,8 @@ extern int current_function_parms_stored; #define AUTO_TEMP_FORMAT "_.tmp_%d" #define VTABLE_BASE ".vb" #define VTABLE_NAME_FORMAT (flag_vtable_thunks ? "__vt_%s" : "_vt.%s") +#define VCTABLE_NAME "__vc." +#define VLIST_NAME_FORMAT "__vl.%s" #define VFIELD_BASE ".vf" #define VFIELD_NAME "_vptr." #define VFIELD_NAME_FORMAT "_vptr.%s" @@ -2346,6 +2383,8 @@ extern int current_function_parms_stored; #define VTABLE_NAME_P(ID_NODE) \ (!strncmp (IDENTIFIER_POINTER (ID_NODE), VTABLE_NAME, \ sizeof (VTABLE_NAME) - 1)) +#define VCTABLE_NAME "__vc_" +#define VLIST_NAME_FORMAT "__vl_%s" #define VFIELD_BASE "__vfb" #define VFIELD_NAME "__vptr_" #define VFIELD_NAME_P(ID_NODE) \ @@ -2379,6 +2418,9 @@ extern int current_function_parms_stored; #define DTOR_NAME "__dt" #define IN_CHARGE_NAME "__in_chrg" +#define VLIST_NAME "__vlist" +#define VLIST1_NAME "__vlist1" +#define VLIST_TYPE_NAME "6_Vlist" #define VTBL_PTR_TYPE "__vtbl_ptr_type" #define VTABLE_DELTA_NAME "__delta" @@ -2556,6 +2598,8 @@ extern tree current_class_name; /* IDENTIFIER_NODE: name of current class */ as well as the space of member functions. LOOKUP_HAS_IN_CHARGE means that the "in charge" variable is already in the parameter list. + LOOKUP_HAS_VLIST means that the "vlist" variable is already in + the parameter list. LOOKUP_ONLYCONVERTING means that non-conversion constructors are not tried. DIRECT_BIND means that if a temporary is created, it should be created so that it lives as long as the current variable bindings; otherwise it @@ -2594,6 +2638,7 @@ extern tree current_class_name; /* IDENTIFIER_NODE: name of current class */ #define LOOKUP_PREFER_NAMESPACES (4096) #define LOOKUP_PREFER_BOTH (6144) #define LOOKUP_TEMPLATES_EXPECTED (8192) +#define LOOKUP_HAS_VLIST (16384) #define LOOKUP_NAMESPACES_ONLY(f) \ (((f) & LOOKUP_PREFER_NAMESPACES) && !((f) & LOOKUP_PREFER_TYPES)) @@ -3051,6 +3096,8 @@ extern tree build_x_delete PROTO((tree, int, tree)); extern tree build_delete PROTO((tree, tree, tree, int, int)); extern tree build_vbase_delete PROTO((tree, tree)); extern tree build_vec_delete PROTO((tree, tree, tree, tree, int)); +extern tree build_base_dtor_call PROTO((tree, tree, tree)); +extern void init_vlist PROTO((tree)); /* in input.c */ @@ -3117,13 +3164,15 @@ extern tree build_decl_overload_real PROTO((tree, tree, tree, tree, extern void set_mangled_name_for_decl PROTO((tree)); extern tree build_typename_overload PROTO((tree)); extern tree build_overload_with_type PROTO((tree, tree)); -extern tree build_destructor_name PROTO((tree)); +extern tree build_destructor_name PROTO((tree, int)); extern tree build_opfncall PROTO((enum tree_code, int, tree, tree, tree)); extern tree hack_identifier PROTO((tree, tree)); extern tree make_thunk PROTO((tree, int)); extern void emit_thunk PROTO((tree)); extern void synthesize_method PROTO((tree)); extern tree get_id_2 PROTO((char *, tree)); +extern tree get_vlist_vtable_id PROTO((tree, tree)); + /* in pt.c */ extern void check_template_shadow PROTO ((tree)); @@ -3200,6 +3249,7 @@ extern tree get_tinfo_fn_dynamic PROTO((tree)); extern tree build_typeid PROTO((tree)); extern tree build_x_typeid PROTO((tree)); extern tree get_tinfo_fn PROTO((tree)); +extern tree get_tinfo_fn_unused PROTO((tree)); extern tree get_typeid PROTO((tree)); extern tree get_typeid_1 PROTO((tree)); extern tree build_dynamic_cast PROTO((tree, tree)); diff --git a/contrib/gcc/cp/decl2.c b/contrib/gcc/cp/decl2.c index bdeadb5..069aaaf 100644 --- a/contrib/gcc/cp/decl2.c +++ b/contrib/gcc/cp/decl2.c @@ -224,14 +224,21 @@ int warn_long_long = 1; int warn_ctor_dtor_privacy = 1; -/* True if we want to implement vtables using "thunks". - The default is off. */ +/* 1 or 2 if we want to implement vtables using "thunks". + The default is off. Version 1 indicates "old" implementation; + Version 2 passes the __vlist argument in pvbase cases. */ #ifndef DEFAULT_VTABLE_THUNKS #define DEFAULT_VTABLE_THUNKS 0 #endif int flag_vtable_thunks = DEFAULT_VTABLE_THUNKS; +#if DEFAULT_VTABLE_THUNKS == 2 +int flag_vtable_thunks_compat = 1; +#else +int flag_vtable_thunks_compat = 0; +#endif + /* True if we want to deal with repository information. */ int flag_use_repository; @@ -633,6 +640,31 @@ lang_decode_option (argc, argv) found = 1; cp_deprecated ("-fexternal-templates"); } + else if (!strncmp (p, "vtable-thunks", 13)) + { + if (p[13] == '=') + { + flag_vtable_thunks = + read_integral_parameter (p+14, p, 1); + } + else + { + /* If the machine file has a default setting, use that + for -fvtable-thunks. Otherwise, set it to version + 2. */ +#if DEFAULT_VTABLE_THUNKS + flag_vtable_thunks = DEFAULT_VTABLE_THUNKS; +#else + flag_vtable_thunks = 1; +#endif + } + if (flag_vtable_thunks == 2) + /* v2 is a compatibility mode between v1 and v3. */ + flag_vtable_thunks_compat = 1; + else if(flag_vtable_thunks == 3) + flag_vtable_thunks_compat = 0; + found = 1; + } else if (!strcmp (p, "handle-signatures")) { flag_handle_signatures = 1; @@ -644,7 +676,7 @@ lang_decode_option (argc, argv) flag_new_abi = 1; flag_do_squangling = 1; flag_honor_std = 1; - flag_vtable_thunks = 1; + flag_vtable_thunks = 2; } else if (!strcmp (p, "no-new-abi")) { @@ -917,17 +949,27 @@ grok_x_components (specs) This function adds the "in-charge" flag to member function FN if appropriate. It is called from grokclassfn and tsubst. - FN must be either a constructor or destructor. */ + FN must be either a constructor or destructor. + + For vtable thunks, types with polymorphic virtual bases need an + additional "vlist" argument which is an array of virtual tables. + In addition, if backwards-compatibility to v1 thunks is requested, + a wrapper constructor may be needed as well. */ void maybe_retrofit_in_chrg (fn) tree fn; { tree basetype, arg_types, parms, parm, fntype; + tree wrapper; + + if (CLASSTYPE_IS_TEMPLATE (DECL_CLASS_CONTEXT (fn))) + /* Never retrofit arguments on template methods. */ + return; if (DECL_CONSTRUCTOR_P (fn) && TYPE_USES_VIRTUAL_BASECLASSES (DECL_CLASS_CONTEXT (fn)) - && ! DECL_CONSTRUCTOR_FOR_VBASE_P (fn)) + && DECL_CONSTRUCTOR_FOR_VBASE (fn) == 0) /* OK */; else if (! DECL_CONSTRUCTOR_P (fn) && TREE_CHAIN (DECL_ARGUMENTS (fn)) == NULL_TREE) @@ -936,7 +978,37 @@ maybe_retrofit_in_chrg (fn) return; if (DECL_CONSTRUCTOR_P (fn)) - DECL_CONSTRUCTOR_FOR_VBASE_P (fn) = 1; + { + if (TYPE_USES_PVBASES (DECL_CLASS_CONTEXT (fn))) + DECL_CONSTRUCTOR_FOR_VBASE (fn) = CONSTRUCTOR_FOR_PVBASE; + else + DECL_CONSTRUCTOR_FOR_VBASE (fn) = CONSTRUCTOR_FOR_VBASE; + } + else if (TYPE_USES_PVBASES (DECL_CLASS_CONTEXT (fn))) + DECL_CONSTRUCTOR_FOR_VBASE (fn) = DESTRUCTOR_FOR_PVBASE; + + /* Retrieve the arguments, because it is potentially modified twice. */ + arg_types = TYPE_ARG_TYPES (TREE_TYPE (fn)); + basetype = TREE_TYPE (TREE_VALUE (arg_types)); + arg_types = TREE_CHAIN (arg_types); + + if (DECL_CONSTRUCTOR_FOR_PVBASE_P (fn) + || DECL_DESTRUCTOR_FOR_PVBASE_P (fn)) + { + /* Add the __vlist argument first. See __in_chrg below. */ + tree id = vlist_identifier; + if (DECL_DESTRUCTOR_FOR_PVBASE_P (fn)) + id = get_identifier (VLIST1_NAME); + parm = build_decl (PARM_DECL, id, vlist_type_node); + SET_DECL_ARTIFICIAL (parm); + DECL_ARG_TYPE (parm) = vlist_type_node; + parms = DECL_ARGUMENTS (fn); + /* Add it after 'this'. */ + TREE_CHAIN (parm) = TREE_CHAIN (parms); + TREE_CHAIN (parms) = parm; + + arg_types = hash_tree_chain (vlist_type_node, arg_types); + } /* First add it to DECL_ARGUMENTS... */ parm = build_decl (PARM_DECL, in_charge_identifier, integer_type_node); @@ -949,15 +1021,17 @@ maybe_retrofit_in_chrg (fn) TREE_CHAIN (parms) = parm; /* ...and then to TYPE_ARG_TYPES. */ - arg_types = TYPE_ARG_TYPES (TREE_TYPE (fn)); - basetype = TREE_TYPE (TREE_VALUE (arg_types)); - arg_types = hash_tree_chain (integer_type_node, TREE_CHAIN (arg_types)); + arg_types = hash_tree_chain (integer_type_node, arg_types); fntype = build_cplus_method_type (basetype, TREE_TYPE (TREE_TYPE (fn)), arg_types); if (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn))) fntype = build_exception_variant (fntype, TYPE_RAISES_EXCEPTIONS (TREE_TYPE (fn))); TREE_TYPE (fn) = fntype; + + if (flag_vtable_thunks_compat + && DECL_CONSTRUCTOR_FOR_PVBASE_P (fn)) + make_vlist_ctor_wrapper (fn); } /* Classes overload their constituent function names automatically. @@ -1042,7 +1116,8 @@ grokclassfn (ctype, function, flags, quals) if (flags == DTOR_FLAG) { - DECL_ASSEMBLER_NAME (function) = build_destructor_name (ctype); + DECL_ASSEMBLER_NAME (function) = + build_destructor_name (ctype, DECL_DESTRUCTOR_FOR_PVBASE_P (function)); TYPE_HAS_DESTRUCTOR (ctype) = 1; } else diff --git a/contrib/gcc/cp/exception.cc b/contrib/gcc/cp/exception.cc index 8e8f35f..59342c6 100644 --- a/contrib/gcc/cp/exception.cc +++ b/contrib/gcc/cp/exception.cc @@ -247,10 +247,10 @@ __cp_pop_exception (cp_eh_info *p) if (p->cleanup) /* 2 is a magic value for destructors; see build_delete(). */ - p->cleanup (p->value, 2); + p->cleanup (p->original_value, 2); // value may have been adjusted. if (! __is_pointer (p->type)) - __eh_free (p->original_value); // value may have been co-erced. + __eh_free (p->original_value); // value may have been adjusted. __eh_free (p); } diff --git a/contrib/gcc/cp/init.c b/contrib/gcc/cp/init.c index 38bf248..aed1fde 100644 --- a/contrib/gcc/cp/init.c +++ b/contrib/gcc/cp/init.c @@ -59,7 +59,8 @@ static tree initializing_context PROTO((tree)); static void expand_vec_init_try_block PROTO((tree)); static void expand_vec_init_catch_clause PROTO((tree, tree, tree, tree)); static tree build_java_class_ref PROTO((tree)); -static void expand_cleanup_for_base PROTO((tree, tree)); +static void expand_cleanup_for_base PROTO((tree, tree, tree)); +static int pvbasecount PROTO((tree, int)); /* Cache the identifier nodes for the magic field of a new cookie. */ static tree nc_nelts_field_id; @@ -478,6 +479,93 @@ sort_base_init (t, rbase_ptr, vbase_ptr) *vbase_ptr = vbases; } +/* Invoke a base-class destructor. REF is the object being destroyed, + BINFO is the base class, and DTOR_ARG indicates whether the base + class should invoke delete. */ + +tree +build_base_dtor_call (ref, binfo, dtor_arg) + tree ref, binfo, dtor_arg; +{ + tree args = NULL_TREE; + tree vlist = lookup_name (vlist_identifier, 0); + tree call, decr; + + if (TYPE_USES_PVBASES (BINFO_TYPE (binfo))) + { + args = expr_tree_cons (NULL_TREE, vlist, args); + dtor_arg = build (BIT_IOR_EXPR, integer_type_node, + dtor_arg, build_int_2 (4, 0)); + dtor_arg = fold (dtor_arg); + } + args = expr_tree_cons (NULL_TREE, dtor_arg, args); + call = build_scoped_method_call (ref, binfo, dtor_identifier, args); + + if (!TYPE_USES_PVBASES (BINFO_TYPE (binfo))) + /* For plain inheritance, do not try to adjust __vlist. */ + return call; + + /* Now decrement __vlist by the number of slots consumed by the base + dtor. */ + decr = build_int_2 (pvbasecount (BINFO_TYPE (binfo), 0), 0); + decr = build_binary_op (MINUS_EXPR, vlist, decr); + decr = build_modify_expr (vlist, NOP_EXPR, decr); + + return build (COMPOUND_EXPR, void_type_node, call, decr); +} + +/* Return the number of vlist entries needed to initialize TYPE, + depending on whether it is IN_CHARGE. */ + +static int +pvbasecount (type, in_charge) + tree type; + int in_charge; +{ + int i; + int result = 0; + tree vbase; + + for (vbase = (CLASSTYPE_VBASECLASSES (type)); vbase; + vbase = TREE_CHAIN (vbase)) + { + result += list_length (CLASSTYPE_VFIELDS (BINFO_TYPE (vbase))); + if (in_charge) + result += pvbasecount (BINFO_TYPE (vbase), 0); + } + + for (i=0; i < CLASSTYPE_N_BASECLASSES (type); i++) + { + tree base = TREE_VEC_ELT (TYPE_BINFO_BASETYPES (type), i); + if (TREE_VIA_VIRTUAL (base)) + continue; + result += pvbasecount (BINFO_TYPE (base), 0); + } + return result; +} + +void +init_vlist (t) + tree t; +{ + char *name; + tree expr; + tree vlist = lookup_name (vlist_identifier, 0); + + name = alloca (strlen (VLIST_NAME_FORMAT) + + TYPE_ASSEMBLER_NAME_LENGTH (t) + 2); + sprintf (name, VLIST_NAME_FORMAT, TYPE_ASSEMBLER_NAME_STRING (t)); + + expr = get_identifier (name); + expr = lookup_name (expr, 0); + expr = build1 (ADDR_EXPR, TREE_TYPE (vlist), expr); + if (DECL_DESTRUCTOR_FOR_PVBASE_P (current_function_decl)) + /* Move to the end of the vlist. */ + expr = build_binary_op (PLUS_EXPR, expr, + build_int_2 (pvbasecount (t, 1), 0)); + expand_expr_stmt (build_modify_expr (vlist, NOP_EXPR, expr)); +} + /* Perform whatever initializations have yet to be done on the base class of the class variable. These actions are in the global variable CURRENT_BASE_INIT_LIST. Such an action could be @@ -510,6 +598,7 @@ emit_base_init (t, immediately) tree binfos = BINFO_BASETYPES (t_binfo); int i, n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0; tree expr = NULL_TREE; + tree vlist = lookup_name (vlist_identifier, 0); if (! immediately) { @@ -581,7 +670,7 @@ emit_base_init (t, immediately) free_temp_slots (); } - expand_cleanup_for_base (base_binfo, NULL_TREE); + expand_cleanup_for_base (base_binfo, vlist, NULL_TREE); rbase_init_list = TREE_CHAIN (rbase_init_list); } @@ -750,30 +839,39 @@ expand_virtual_init (binfo, decl) destroyed. */ static void -expand_cleanup_for_base (binfo, flag) +expand_cleanup_for_base (binfo, vlist, flag) tree binfo; + tree vlist; tree flag; { tree expr; - if (!TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (binfo))) - return; + if (TYPE_NEEDS_DESTRUCTOR (BINFO_TYPE (binfo))) + { + /* All cleanups must be on the function_obstack. */ + push_obstacks_nochange (); + resume_temporary_allocation (); - /* All cleanups must be on the function_obstack. */ - push_obstacks_nochange (); - resume_temporary_allocation (); + /* Call the destructor. */ + expr = build_base_dtor_call (current_class_ref, binfo, + integer_zero_node); + if (flag) + expr = fold (build (COND_EXPR, void_type_node, + truthvalue_conversion (flag), + expr, integer_zero_node)); - /* Call the destructor. */ - expr = (build_scoped_method_call - (current_class_ref, binfo, dtor_identifier, - build_expr_list (NULL_TREE, integer_zero_node))); - if (flag) - expr = fold (build (COND_EXPR, void_type_node, - truthvalue_conversion (flag), - expr, integer_zero_node)); + pop_obstacks (); + add_partial_entry (expr); + } - pop_obstacks (); - add_partial_entry (expr); + if (TYPE_USES_PVBASES (BINFO_TYPE (binfo))) + { + /* Increment vlist by number of base's vbase classes. */ + expr = build_int_2 (pvbasecount (BINFO_TYPE (binfo), 0), 0); + expr = build_binary_op (PLUS_EXPR, vlist, expr); + expr = build_modify_expr (vlist, NOP_EXPR, expr); + expand_expr_stmt (expr); + } } /* Subroutine of `expand_aggr_vbase_init'. @@ -813,6 +911,7 @@ construct_virtual_bases (type, this_ref, this_ptr, init_list, flag) { tree vbases; tree result; + tree vlist = NULL_TREE; /* If there are no virtual baseclasses, we shouldn't even be here. */ my_friendly_assert (TYPE_USES_VIRTUAL_BASECLASSES (type), 19990621); @@ -820,6 +919,11 @@ construct_virtual_bases (type, this_ref, this_ptr, init_list, flag) /* First set the pointers in our object that tell us where to find our virtual baseclasses. */ expand_start_cond (flag, 0); + if (TYPE_USES_PVBASES (type)) + { + init_vlist (type); + vlist = lookup_name (vlist_identifier, 0); + } result = init_vbase_pointers (type, this_ptr); if (result) expand_expr_stmt (build_compound_expr (result)); @@ -851,7 +955,7 @@ construct_virtual_bases (type, this_ref, this_ptr, init_list, flag) init_list); expand_end_cond (); - expand_cleanup_for_base (vbases, flag); + expand_cleanup_for_base (vbases, vlist, flag); } } @@ -1146,6 +1250,44 @@ expand_aggr_init (exp, init, flags) TREE_THIS_VOLATILE (exp) = was_volatile; } +static tree +no_vlist_base_init (rval, exp, init, binfo, flags) + tree rval, exp, init, binfo; + int flags; +{ + tree nrval, func, parms; + + /* Obtain the vlist-expecting ctor. */ + func = rval; + my_friendly_assert (TREE_CODE (func) == CALL_EXPR, 20000131); + func = TREE_OPERAND (func, 0); + my_friendly_assert (TREE_CODE (func) == ADDR_EXPR, 20000132); + + if (init == NULL_TREE + || (TREE_CODE (init) == TREE_LIST && ! TREE_TYPE (init))) + { + parms = init; + if (parms) + init = TREE_VALUE (parms); + } + else + parms = build_expr_list (NULL_TREE, init); + + flags &= ~LOOKUP_HAS_VLIST; + + parms = expr_tree_cons (NULL_TREE, integer_zero_node, parms); + flags |= LOOKUP_HAS_IN_CHARGE; + + nrval = build_method_call (exp, ctor_identifier, + parms, binfo, flags); + + func = build (NE_EXPR, boolean_type_node, + func, null_pointer_node); + nrval = build (COND_EXPR, void_type_node, + func, rval, nrval); + return nrval; +} + static void expand_default_init (binfo, true_exp, exp, init, flags) tree binfo; @@ -1163,6 +1305,8 @@ expand_default_init (binfo, true_exp, exp, init, flags) out, then look hard. */ tree rval; tree parms; + tree vlist = NULL_TREE; + tree orig_init = init; if (init && TREE_CODE (init) != TREE_LIST && (flags & LOOKUP_ONLYCONVERTING)) @@ -1206,6 +1350,21 @@ expand_default_init (binfo, true_exp, exp, init, flags) if (TYPE_USES_VIRTUAL_BASECLASSES (type)) { + if (TYPE_USES_PVBASES (type)) + { + /* In compatibility mode, when not calling a base ctor, + we do not pass the vlist argument. */ + if (true_exp == exp) + vlist = flag_vtable_thunks_compat? NULL_TREE : vlist_zero_node; + else + vlist = lookup_name (vlist_identifier, 0); + + if (vlist) + { + parms = expr_tree_cons (NULL_TREE, vlist, parms); + flags |= LOOKUP_HAS_VLIST; + } + } if (true_exp == exp) parms = expr_tree_cons (NULL_TREE, integer_one_node, parms); else @@ -1215,6 +1374,10 @@ expand_default_init (binfo, true_exp, exp, init, flags) rval = build_method_call (exp, ctor_identifier, parms, binfo, flags); + if (vlist && true_exp != exp && flag_vtable_thunks_compat) + { + rval = no_vlist_base_init (rval, exp, orig_init, binfo, flags); + } if (TREE_SIDE_EFFECTS (rval)) expand_expr_stmt (rval); } @@ -2408,6 +2571,12 @@ build_new_1 (exp) if (rval && TYPE_USES_VIRTUAL_BASECLASSES (true_type)) { + if (TYPE_USES_PVBASES (true_type) + && !flag_vtable_thunks_compat) + { + init = expr_tree_cons (NULL_TREE, vlist_zero_node, init); + flags |= LOOKUP_HAS_VLIST; + } init = expr_tree_cons (NULL_TREE, integer_one_node, init); flags |= LOOKUP_HAS_IN_CHARGE; } @@ -3123,9 +3292,21 @@ build_delete (type, addr, auto_delete, flags, use_global_delete) else passed_auto_delete = auto_delete; - expr = build_method_call - (ref, dtor_identifier, build_expr_list (NULL_TREE, passed_auto_delete), - NULL_TREE, flags); + /* Maybe pass vlist pointer to destructor. */ + if (TYPE_USES_PVBASES (type)) + { + /* Pass vlist_zero even if in backwards compatibility mode, + as the extra argument should not hurt if it is not used. */ + expr = build_expr_list (NULL_TREE, vlist_zero_node); + flags |= LOOKUP_HAS_VLIST; + } + else + expr = NULL_TREE; + + expr = expr_tree_cons (NULL_TREE, passed_auto_delete, expr); + + expr = build_method_call (ref, dtor_identifier, expr, + NULL_TREE, flags); if (do_delete) expr = build (COMPOUND_EXPR, void_type_node, expr, do_delete); @@ -3181,14 +3362,13 @@ build_delete (type, addr, auto_delete, flags, use_global_delete) { tree this_auto_delete; + /* Should the base invoke delete? */ if (BINFO_OFFSET_ZEROP (base_binfo)) this_auto_delete = parent_auto_delete; else this_auto_delete = integer_zero_node; - expr = build_scoped_method_call - (ref, base_binfo, dtor_identifier, - build_expr_list (NULL_TREE, this_auto_delete)); + expr = build_base_dtor_call (ref, base_binfo, this_auto_delete); exprstmt = expr_tree_cons (NULL_TREE, expr, exprstmt); } @@ -3200,9 +3380,7 @@ build_delete (type, addr, auto_delete, flags, use_global_delete) || TREE_VIA_VIRTUAL (base_binfo)) continue; - expr = build_scoped_method_call - (ref, base_binfo, dtor_identifier, - build_expr_list (NULL_TREE, integer_zero_node)); + expr = build_base_dtor_call (ref, base_binfo, integer_zero_node); exprstmt = expr_tree_cons (NULL_TREE, expr, exprstmt); } diff --git a/contrib/gcc/cp/method.c b/contrib/gcc/cp/method.c index d4a667b..d60bfda 100644 --- a/contrib/gcc/cp/method.c +++ b/contrib/gcc/cp/method.c @@ -41,6 +41,7 @@ Boston, MA 02111-1307, USA. */ #include "hard-reg-set.h" #include "flags.h" #include "toplev.h" +#include "decl.h" /* TREE_LIST of the current inline functions that need to be processed. */ @@ -88,6 +89,8 @@ static int is_back_referenceable_type PROTO((tree)); static int check_btype PROTO((tree)); static void build_mangled_name_for_type PROTO((tree)); static void build_mangled_name_for_type_with_Gcode PROTO((tree, int)); +static tree build_base_path PROTO((tree, int)); + # define OB_INIT() (scratch_firstobj ? (obstack_free (&scratch_obstack, scratch_firstobj), 0) : 0) # define OB_PUTC(C) (obstack_1grow (&scratch_obstack, (C))) @@ -1349,6 +1352,15 @@ process_overload_item (parmtype, extra_Gcode) #endif case POINTER_TYPE: + /* Even though the vlist_type_node is PPPFe (i.e. `int + (***)(...)'), it is different from the any other occurence of + the pointer type, because the underlying function type is + different. */ + if (parmtype == vlist_type_node) + { + OB_PUTS (VLIST_TYPE_NAME); + return; + } OB_PUTC ('P'); more: build_mangled_name_for_type (TREE_TYPE (parmtype)); @@ -1809,14 +1821,64 @@ get_id_2 (name, name2) return get_identifier (obstack_base (&scratch_obstack)); } -/* Returns a DECL_ASSEMBLER_NAME for the destructor of type TYPE. */ +/* Print a binfo path T, starting with the most derived class. If + OMIT_LAST is set, drop and return the most derived class. */ + +static tree +build_base_path (t, omit_last) + tree t; + int omit_last; +{ + tree ret = NULL_TREE; + if (BINFO_INHERITANCE_CHAIN (t)) + ret = build_base_path (BINFO_INHERITANCE_CHAIN (t), omit_last); + else if (omit_last) + return t; + process_overload_item (BINFO_TYPE (t), 0); + return ret; +} + +/* Return a mangled name for a vlist vtable, using the path of both + BASE and VBASE. */ + +tree +get_vlist_vtable_id (base, vbase) + tree base, vbase; +{ + tree last; + OB_INIT (); + OB_PUTS (VCTABLE_NAME); + build_base_path (base, 0); + OB_PUTC ('_'); + /* Since the base path should end where the vbase path starts, we + can omit the most-derived class in the vbase path. Check below + that this really happens. */ + last = build_base_path (vbase, 1); + my_friendly_assert (BINFO_TYPE (last) == BINFO_TYPE (base), 990402); + OB_FINISH (); + return get_identifier (obstack_base (&scratch_obstack)); +} + +/* Returns a DECL_ASSEMBLER_NAME for the destructor of type TYPE. If + HAS_VLIST is set, also add the vlist argument. */ tree -build_destructor_name (type) +build_destructor_name (type, has_vlist) tree type; + int has_vlist; { - return build_overload_with_type (get_identifier (DESTRUCTOR_DECL_PREFIX), - type); + OB_INIT (); + OB_PUTS (DESTRUCTOR_DECL_PREFIX); + start_squangling (); + build_mangled_name_for_type (type); + /* If we need backwards compatibility, we can get aways by + not linking type-safely, as the dtor will check whether + the argument was provided. */ + if (has_vlist && !flag_vtable_thunks_compat) + OB_PUTS (VLIST_TYPE_NAME); + OB_FINISH (); + end_squangling (); + return get_identifier (obstack_base (&scratch_obstack)); } /* Given a tree_code CODE, and some arguments (at least one), @@ -2178,6 +2240,136 @@ emit_thunk (thunk_fndecl) TREE_SET_CODE (thunk_fndecl, THUNK_DECL); } +void +make_vlist_ctor_wrapper (fn) + tree fn; +{ + tree fntype, decl; + tree arg_types, parms, parm, basetype, pbasetype; + tree t, ctors; + + arg_types = TYPE_ARG_TYPES (TREE_TYPE (fn)); + pbasetype = TREE_VALUE (arg_types); + basetype = TREE_TYPE (pbasetype); + parms = DECL_ARGUMENTS (fn); + + /* Skip this, __in_chrg, and _vlist */ + arg_types = TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (arg_types))); + + + /* Add __in_charge. */ + arg_types = hash_tree_chain (integer_type_node, arg_types); + + /* Don't add this to arg_types, as build_cplus_method_type does so. */ + + fntype = build_cplus_method_type (basetype, TREE_TYPE (TREE_TYPE (fn)), + arg_types); + + decl = build_lang_decl (FUNCTION_DECL, DECL_NAME (fn), fntype); + DECL_LANG_SPECIFIC (decl)->decl_flags = DECL_LANG_SPECIFIC (fn)->decl_flags; + DECL_EXTERNAL (decl) = 0; + TREE_PUBLIC (decl) = 1; + DECL_ARTIFICIAL (decl) = 1; + DECL_CONSTRUCTOR_P (decl) = 1; + DECL_CONSTRUCTOR_FOR_VBASE (decl) = CONSTRUCTOR_FOR_VBASE; + /* Claim that this is never a template instantiation. */ + DECL_USE_TEMPLATE (decl) = 0; + DECL_TEMPLATE_INFO (decl) = NULL_TREE; + + /* Set up clone argument trees for the thunk. */ + parms = TREE_CHAIN (TREE_CHAIN (TREE_CHAIN (parms))); + /* Add this */ + t = build_decl (PARM_DECL, this_identifier, pbasetype); + SET_DECL_ARTIFICIAL (t); + DECL_ARG_TYPE (t) = pbasetype; + DECL_REGISTER (t) = 1; + /* Add __in_charge. */ + parm = build_decl (PARM_DECL, in_charge_identifier, integer_type_node); + SET_DECL_ARTIFICIAL (parm); + DECL_ARG_TYPE (parm) = integer_type_node; + TREE_CHAIN (parm) = t; + t = parm; + + while (parms) + { + tree x = copy_node (parms); + TREE_CHAIN (x) = t; + DECL_CONTEXT (x) = decl; + t = x; + parms = TREE_CHAIN (parms); + } + parms = nreverse (t); + DECL_ARGUMENTS (decl) = parms; + + DECL_ASSEMBLER_NAME (decl) + = build_decl_overload (DECL_NAME (decl), + TYPE_ARG_TYPES (TREE_TYPE (decl)), 2); + + ctors = CLASSTYPE_METHOD_VEC (basetype); + if (ctors) + ctors = TREE_VEC_ELT (ctors, 0); + for ( ; ctors; ctors = OVL_NEXT (ctors)) + if (DECL_ASSEMBLER_NAME (OVL_CURRENT (ctors)) + == DECL_ASSEMBLER_NAME (decl)) + break; + + if (!ctors) + { + add_method (basetype, 0, decl); + cp_finish_decl (decl, NULL_TREE, NULL_TREE, 0, 0); + } + else + decl = OVL_CURRENT (ctors); + + /* Remember the original function. */ + DECL_VLIST_CTOR_WRAPPED (decl) = fn; + + /* When fn is declared, DECL_INITIAL is null. When it is defined, + DECL_INITIAL will be error_mark_node. */ + if (DECL_INITIAL (fn) == error_mark_node) + { + /* Record that the ctor is being defined, so we also emit the + wrapper later. */ + TREE_USED (decl) = 1; + DECL_NOT_REALLY_EXTERN (decl) = 1; + DECL_INITIAL (decl) = NULL_TREE; + mark_inline_for_output (decl); + } +} + +static void +emit_vlist_ctor_wrapper (decl) + tree decl; +{ + tree t, parms, fn; + + current_function_is_thunk = 1; + + parms = DECL_ARGUMENTS (decl); + fn = DECL_VLIST_CTOR_WRAPPED (decl); + mark_used (fn); + + /* Build up the call to the real function. */ + t = NULL_TREE; + /* Push this, __in_charge. */ + t = expr_tree_cons (NULL_TREE, parms, t); + parms = TREE_CHAIN (parms); + t = expr_tree_cons (NULL_TREE, parms, t); + parms = TREE_CHAIN (parms); + /* Push 0 as __vlist. */ + t = expr_tree_cons (NULL_TREE, vlist_zero_node, t); + /* Push rest of arguments. */ + while (parms) + { + t = expr_tree_cons (NULL_TREE, parms, t); + parms = TREE_CHAIN (parms); + } + t = nreverse (t); + t = build_call (fn, TREE_TYPE (TREE_TYPE (fn)), t); + expand_expr_stmt (t); +} + + /* Code for synthesizing methods which have default semantics defined. */ /* For the anonymous union in TYPE, return the member that is at least as @@ -2212,6 +2404,8 @@ do_build_copy_constructor (fndecl) if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type)) parm = TREE_CHAIN (parm); + if (TYPE_USES_PVBASES (current_class_type)) + parm = TREE_CHAIN (parm); parm = convert_from_reference (parm); if (TYPE_HAS_TRIVIAL_INIT_REF (current_class_type) @@ -2408,6 +2602,16 @@ synthesize_method (fndecl) int nested = (current_function_decl != NULL_TREE); tree context = hack_decl_function_context (fndecl); + /* If this is a wrapper around a undefined vlist ctor, don't emit it + even if it is used. */ + if (DECL_VLIST_CTOR_WRAPPER_P (fndecl)) + { + tree orig_fn = DECL_VLIST_CTOR_WRAPPED (fndecl); + mark_used (orig_fn); + if (DECL_INITIAL (orig_fn) == NULL_TREE) + return; + } + if (at_eof) import_export_decl (fndecl); @@ -2429,7 +2633,11 @@ synthesize_method (fndecl) tree arg_chain = FUNCTION_ARG_CHAIN (fndecl); if (DECL_CONSTRUCTOR_FOR_VBASE_P (fndecl)) arg_chain = TREE_CHAIN (arg_chain); - if (arg_chain != void_list_node) + else if (DECL_CONSTRUCTOR_FOR_PVBASE_P (fndecl)) + arg_chain = TREE_CHAIN (TREE_CHAIN (arg_chain)); + if (DECL_VLIST_CTOR_WRAPPER_P (fndecl)) + emit_vlist_ctor_wrapper (fndecl); + else if (arg_chain != void_list_node) do_build_copy_constructor (fndecl); else if (TYPE_NEEDS_CONSTRUCTING (current_class_type)) setup_vtbl_ptr (); @@ -2443,3 +2651,6 @@ synthesize_method (fndecl) else if (nested) pop_cp_function_context (context); } + + + diff --git a/contrib/gcc/cp/pt.c b/contrib/gcc/cp/pt.c index ddbea0a..28c2956 100644 --- a/contrib/gcc/cp/pt.c +++ b/contrib/gcc/cp/pt.c @@ -161,6 +161,7 @@ static int coerce_template_template_parms PROTO((tree, tree, int, static tree determine_specialization PROTO((tree, tree, tree *, int)); static int template_args_equal PROTO((tree, tree)); static void print_template_context PROTO((int)); +static int has_pvbases_p PROTO((tree, tree)); /* We use TREE_VECs to hold template arguments. If there is only one level of template arguments, then the TREE_VEC contains the @@ -4685,6 +4686,23 @@ tsubst_friend_class (friend_tmpl, args) return friend_type; } +static int +has_pvbases_p (t, pattern) + tree t, pattern; +{ + if (!TYPE_USES_VIRTUAL_BASECLASSES (t)) + return 0; + + if (TYPE_USES_PVBASES (pattern)) + return 1; + + for (t = CLASSTYPE_VBASECLASSES (t); t; t = TREE_CHAIN (t)) + if (TYPE_VIRTUAL_P (BINFO_TYPE (t))) + return 1; + + return 0; +} + tree instantiate_class_template (type) tree type; @@ -5035,6 +5053,13 @@ instantiate_class_template (type) } } + /* After we have calculated the bases, we can now compute whether we + have polymorphic vbases. This needs to happen before we + instantiate the methods, because the constructors may take + additional arguments. */ + if (flag_vtable_thunks >= 2) + TYPE_USES_PVBASES (type) = has_pvbases_p (type, pattern); + /* Set up the list (TYPE_METHODS) and vector (CLASSTYPE_METHOD_VEC) for this instantiation. */ for (t = TYPE_METHODS (pattern); t; t = TREE_CHAIN (t)) @@ -5716,9 +5741,17 @@ tsubst_decl (t, args, type, in_decl) SET_DECL_IMPLICIT_INSTANTIATION (r); register_specialization (r, gen_tmpl, argvec); + + if (DECL_CONSTRUCTOR_P (r) || DECL_DESTRUCTOR_P (r)) + { + maybe_retrofit_in_chrg (r); + grok_ctor_properties (ctx, r); + } + /* Set the mangled name for R. */ if (DECL_DESTRUCTOR_P (t)) - DECL_ASSEMBLER_NAME (r) = build_destructor_name (ctx); + DECL_ASSEMBLER_NAME (r) = + build_destructor_name (ctx, DECL_DESTRUCTOR_FOR_PVBASE_P (r)); else { /* Instantiations of template functions must be mangled @@ -5761,11 +5794,14 @@ tsubst_decl (t, args, type, in_decl) in_decl); } +#if 0 + /* This has now moved further up. */ if (DECL_CONSTRUCTOR_P (r)) { maybe_retrofit_in_chrg (r); grok_ctor_properties (ctx, r); } +#endif if (IDENTIFIER_OPNAME_P (DECL_NAME (r))) grok_op_properties (r, DECL_VIRTUAL_P (r), DECL_FRIEND_P (r)); } diff --git a/contrib/gcc/cp/rtti.c b/contrib/gcc/cp/rtti.c index e0ce5cd..c8c1ba9 100644 --- a/contrib/gcc/cp/rtti.c +++ b/contrib/gcc/cp/rtti.c @@ -363,8 +363,19 @@ get_tinfo_var (type) return tdecl; } +/* Returns the decl for a function which will return a type_info node for + TYPE. This version does not mark the function used, for use in + set_rtti_entry; for the vtable case, we'll get marked in + finish_vtable_vardecl, when we know that we want to be emitted. + + We do this to avoid emitting the tinfo node itself, since we don't + currently support DECL_DEFER_OUTPUT for variables. Also, we don't + associate constant pools with their functions properly, so we would + emit string constants and such even though we don't emit the actual + function. When those bugs are fixed, this function should go away. */ + tree -get_tinfo_fn (type) +get_tinfo_fn_unused (type) tree type; { tree name; @@ -393,13 +404,23 @@ get_tinfo_fn (type) pushdecl_top_level (d); make_function_rtl (d); - mark_used (d); mark_inline_for_output (d); pop_obstacks (); return d; } +/* Likewise, but also mark it used. Called by various EH and RTTI code. */ + +tree +get_tinfo_fn (type) + tree type; +{ + tree d = get_tinfo_fn_unused (type); + mark_used (d); + return d; +} + tree get_typeid_1 (type) tree type; diff --git a/contrib/gcc/cp/search.c b/contrib/gcc/cp/search.c index 8760c6a..fb99f8f 100644 --- a/contrib/gcc/cp/search.c +++ b/contrib/gcc/cp/search.c @@ -151,6 +151,9 @@ static int protected_accessible_p PROTO ((tree, tree, tree, tree)); static int friend_accessible_p PROTO ((tree, tree, tree, tree)); static void setup_class_bindings PROTO ((tree, int)); static int template_self_reference_p PROTO ((tree, tree)); +static void expand_direct_vtbls_init_thunks PROTO((tree, tree, int)); +static void expand_indirect_vtbls_init_thunks PROTO((tree, tree, tree)); + /* Allocate a level of searching. */ @@ -2626,6 +2629,117 @@ fixup_virtual_upcast_offsets (real_binfo, binfo, init_self, can_elide, addr, ori } } +/* Emit initialization of vfields of BASE, where the complete object + is pointed to by decl_ptr. DO_SELF indicates we have to do our own + vfield, otherwise only proceed to our own direct non-virtual bases. */ + +static void +expand_direct_vtbls_init_thunks (base, decl_ptr, do_self) + tree base, decl_ptr; + int do_self; +{ + tree addr, expr; + tree type = BINFO_TYPE (base); + tree binfos = BINFO_BASETYPES (base); + int i, n_baselinks = binfos ? TREE_VEC_LENGTH (binfos) : 0; + tree vlist = lookup_name (vlist_identifier, 0); + int in_dtor = DECL_DESTRUCTOR_FOR_PVBASE_P (current_function_decl); + + my_friendly_assert (vlist != NULL_TREE, 990320); + + if (in_dtor) + /* In the destructor, we find the vfield pointers for the bases in + reverse order, before we find our own vfield pointer. */ + for (i = n_baselinks - 1; i >= 0; i--) + { + tree base_binfo = TREE_VEC_ELT (binfos, i); + int is_not_base_vtable + = i != CLASSTYPE_VFIELD_PARENT (type); + if (! TREE_VIA_VIRTUAL (base_binfo)) + expand_direct_vtbls_init_thunks (base_binfo, decl_ptr, + is_not_base_vtable); + } + + if (do_self && CLASSTYPE_VFIELDS (type)) + { + addr = build_vbase_path (PLUS_EXPR, build_pointer_type (type), + decl_ptr, base, 1); + addr = build_indirect_ref (addr, "vptr"); + addr = build_vfield_ref (addr, type); + + /* In a destructor, we decrease the vlist before we retrieve the + value. In a constructor, we increase the vlist after we + retrieve the value. */ + if (in_dtor) + { + expr = build_binary_op (MINUS_EXPR, vlist, integer_one_node); + expr = build_modify_expr (vlist, NOP_EXPR, expr); + expand_expr_stmt (expr); + } + + /* Store the next vptr into the vbase's vptr. */ + expr = build_indirect_ref (vlist, "__vlist"); + expr = convert_force (TREE_TYPE (addr), expr, 0); + expr = build_modify_expr (addr, NOP_EXPR, expr); + expand_expr_stmt (expr); + + /* Advance the vlist. */ + if (!in_dtor) + { + expr = build_binary_op (PLUS_EXPR, vlist, integer_one_node); + expr = build_modify_expr (vlist, NOP_EXPR, expr); + expand_expr_stmt (expr); + } + } + + if (!in_dtor) + for (i = 0; i < n_baselinks; i++) + { + tree base_binfo = TREE_VEC_ELT (binfos, i); + int is_not_base_vtable = i != CLASSTYPE_VFIELD_PARENT (type); + if (! TREE_VIA_VIRTUAL (base_binfo)) + expand_direct_vtbls_init_thunks (base_binfo, decl_ptr, + is_not_base_vtable); + } +} + +/* Like expand_indirect_vtbls_init below, but based on the vtable list + passed to the constructor. */ + +static void +expand_indirect_vtbls_init_thunks (binfo, true_exp, decl_ptr) + tree binfo; + tree true_exp, decl_ptr; +{ + tree type = BINFO_TYPE (binfo); + tree vbases = CLASSTYPE_VBASECLASSES (type); + struct vbase_info vi; + + vi.decl_ptr = (true_exp ? build_unary_op (ADDR_EXPR, true_exp, 0) + : decl_ptr); + vi.vbase_types = vbases; + + dfs_walk (binfo, dfs_find_vbases, unmarked_new_vtablep, &vi); + + /* Initialized with vtables of type TYPE. */ + for (; vbases; vbases = TREE_CHAIN (vbases)) + { + tree addr; + + if (!CLASSTYPE_VFIELD (BINFO_TYPE (vbases))) + /* This vbase doesn't have a vptr of its own. */ + /* FIXME: check */ + continue; + + addr = convert_pointer_to_vbase (TREE_TYPE (vbases), decl_ptr); + expand_direct_vtbls_init_thunks (TYPE_BINFO (BINFO_TYPE (vbases)), + addr, 1); + + } + + dfs_walk (binfo, dfs_clear_vbase_slots, marked_new_vtablep, 0); +} + /* Build a COMPOUND_EXPR which when expanded will generate the code needed to initialize all the virtual function table slots of all the virtual baseclasses. MAIN_BINFO is the binfo which determines @@ -2657,6 +2771,12 @@ expand_indirect_vtbls_init (binfo, true_exp, decl_ptr) mark_all_temps_used(); + if (TYPE_USES_PVBASES (type)) + { + expand_indirect_vtbls_init_thunks (binfo, true_exp, decl_ptr); + return; + } + if (TYPE_USES_VIRTUAL_BASECLASSES (type)) { rtx fixup_insns = NULL_RTX; |