diff options
Diffstat (limited to 'gnu/egcs/gcc/cp')
-rw-r--r-- | gnu/egcs/gcc/cp/ChangeLog | 123 | ||||
-rw-r--r-- | gnu/egcs/gcc/cp/class.c | 354 | ||||
-rw-r--r-- | gnu/egcs/gcc/cp/exception.cc | 4 | ||||
-rw-r--r-- | gnu/egcs/gcc/cp/gxxint.texi | 233 | ||||
-rw-r--r-- | gnu/egcs/gcc/cp/init.c | 234 | ||||
-rw-r--r-- | gnu/egcs/gcc/cp/method.c | 221 | ||||
-rw-r--r-- | gnu/egcs/gcc/cp/rtti.c | 25 | ||||
-rw-r--r-- | gnu/egcs/gcc/cp/search.c | 120 | ||||
-rw-r--r-- | gnu/egcs/gcc/cp/typeck2.c | 4 |
9 files changed, 1275 insertions, 43 deletions
diff --git a/gnu/egcs/gcc/cp/ChangeLog b/gnu/egcs/gcc/cp/ChangeLog index efa30edcad2..3f005333b88 100644 --- a/gnu/egcs/gcc/cp/ChangeLog +++ b/gnu/egcs/gcc/cp/ChangeLog @@ -1,3 +1,126 @@ +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. + +1999-11-01 Jason Merrill <jason@yorick.cygnus.com> + + * decl2.c (maybe_make_one_only): Always make things comdat on + ELF targets, too. + Sun Oct 24 23:54:10 PDT 1999 Jeff Law (law@cygnus.com) * gcc-2.95.2 Released. diff --git a/gnu/egcs/gcc/cp/class.c b/gnu/egcs/gcc/cp/class.c index 400c67de41a..74808c56f35 100644 --- a/gnu/egcs/gcc/cp/class.c +++ b/gnu/egcs/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/gnu/egcs/gcc/cp/exception.cc b/gnu/egcs/gcc/cp/exception.cc index 8e8f35f50db..59342c6423e 100644 --- a/gnu/egcs/gcc/cp/exception.cc +++ b/gnu/egcs/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/gnu/egcs/gcc/cp/gxxint.texi b/gnu/egcs/gcc/cp/gxxint.texi index 05f1373b252..81bcab86425 100644 --- a/gnu/egcs/gcc/cp/gxxint.texi +++ b/gnu/egcs/gcc/cp/gxxint.texi @@ -26,6 +26,7 @@ Questions and comments to Benjamin Kosnik @code{<bkoz@@cygnus.com>}. * Exception Handling:: * Free Store:: * Mangling:: Function name mangling for C++ and Java +* Vtables:: Two ways to do virtual functions * Concept Index:: @end menu @@ -190,7 +191,9 @@ accessed by the BINFO_ accessor macros. The virtual function table holds information used in virtual function dispatching. In the compiler, they are usually referred to as vtables, or vtbls. The first index is not used in the normal way, I believe it -is probably used for the virtual destructor. +is probably used for the virtual destructor. There are two forms of +virtual tables, one that has offsets in addition to pointers, and one +using thunks. @xref{Vtables}. @item vfield @@ -1455,7 +1458,7 @@ To meet the first goal, we defer emission of inlines and vtables until the end of the translation unit, where we can decide whether or not they are needed, and how to emit them if they are. -@node Mangling, Concept Index, Free Store, Top +@node Mangling, Vtables, Free Store, Top @section Function name mangling for C++ and Java Both C++ and Jave provide overloaded function and methods, @@ -1839,7 +1842,231 @@ Used for template type parameters. The letters @samp{G}, @samp{M}, @samp{O}, and @samp{p} also seem to be used for obscure purposes ... -@node Concept Index, , Mangling, Top +@node Vtables, Concept Index, Mangling, Top +@section Virtual Tables + +In order to invoke virtual functions, GNU C++ uses virtual tables. Each +virtual function gets an index, and the table entry points to the +overridden function to call. Sometimes, and adjustment to the this +pointer has to be made before calling a virtual function: + +@example +struct A@{ + int i; + virtual void foo(); +@}; + +struct B@{ + int j; + virtual void bar(); +@}; + +struct C:A,B@{ + virtual void bar(); +@}; + +void C::bar() +@{ + i++; +@} + +int main() +@{ + C *c = new C; + B *b = c; + c->bar(); +@} +@end example + +Here, casting from @samp{c} to @samp{b} adds an offset. When @samp{bar} +is called, this offset needs to be subtracted, so that @samp{C::bar} can +properly access @samp{i}. One approach of achieving this is to use +@emph{thunks}, which are small half-functions put into the virtual +table. The modify the first argument (the @samp{this} pointer), and then +jump into the real function. + +The other (traditional) approach is to have an additional integer in the +virtual table which is added to this. This is an additional overhead +both at the function call, and in the size of virtual tables: In the +case of single inheritance (or for the first base class), these integers +will always be zero. + +@subsection Virtual Base Classes with Virtual Tables + +In case of virtual bases, the code is even more +complicated. Constructors and destructors need to know whether they are +"in charge" of the virtual bases, and an implicit integer +@samp{__in_chrg} for that purpose. + +@example +struct A@{ + int i; + virtual void bar(); + void call_bar()@{bar();@} +@}; + +struct B:virtual A@{ + B(); + int j; + virtual void bar(); +@}; + +B::B()@{ + call_bar(); +@} + +struct C@{ + int k; +@}; + +struct D:C,B@{ + int l; + virtual void bar(); +@}; + +@end example + +When constructing an instance of B, it will have the following layout: +@samp{vbase pointer to A}, @samp{j}, @samp{A virtual table}, @samp{i}. +On a 32-bit machine, downcasting from @samp{A*} to @samp{B*} would need +to subtract 8, which would be the thunk executed when calling +@samp{B::bar} inside @samp{call_bar}. + +When constructing an instance of D, it will have a different layout: +@samp{k}, @samp{vbase pointer to A}, @samp{j}, @samp{l}, @samp{A virtual +table}, @samp{i}. So, when downcasting from @samp{A*} to @samp{B*} in a +@samp{D} object, the offset would be @samp{12}. + +This means that during construction of the @samp{B} base of a @samp{D} +object, a virtual table is needed which has a @samp{-12} thunk to +@samp{B::bar}. This is @emph{only} needed during construction and +destruction, as the full object will use a @samp{-16} thunk to +@samp{D::bar}. + +In order to implement this, the compiler generates an implicit argument +(in addition to @code{__in_chrg}): the virtual list argument +@code{__vlist}. This is a list of virtual tables needed during +construction and destruction. The virtual pointers are ordered in the +way they are used during construction; the destructors will process the +array in reverse order. The ordering is as follows: +@itemize @bullet +@item +If the class is in charge, the vlist starts with virtual table pointers +for the virtual bases that have virtual bases themselves. Here, only +@emph{polymorphic} virtual bases (pvbases) are interesting: if a vbase +has no virtual functions, it doesn't have a virtual table. + +@item +Next, the vlist has virtual tables for the initialization of the +non-virtual bases. These bases are not in charge, so the layout is +recursive, but ignores virtual bases during recursion. + +@item +Next, there is a number of virtual tables for each virtual base. These +are sorted in the order in which virtual bases are constructed. Each +virtual base may have more than one @code{vfield}, and therefore require +more than one @code{vtable}. The order of vtables is the same as used +when initializing vfields of non-virtual bases in a constructor. +@end itemize + +The compiler emits a virtual table list in a variable mangled as +@code{__vl.classname}. + +Class with virtual bases, but without pvbases, only have the +@code{__in_chrg} argument to their ctors and dtors: they don't have any +vfields in the vbases to initialize. + +A further problem arises with virtual destructors: A destructor +typically has only the @code{__in_chrg} argument, which also indicates +whether the destructor should call @code{operator delete}. A dtor of a +class with pvbases has an additional argument. Unfortunately, a caller +of a virtual dtor might not know whether to pass that argument or not. +Therefore, the dtor processes the @code{__vlist} argument in an +automatic variable, which is initialized from the class' vlist if the +__in_chrg flag has a zero value in bit 2 (bit mask 4), or from the +argument @code{__vlist1} if bit 2 of the __in_chrg parameter is set to +one. + +@subsection Specification of non-thunked vtables + +In the traditional implementation of vtables, each slot contains three +fields: The offset to be added to the this pointer before invoking a +virtual function, an unused field that is always zero, and the pointer +to the virtual function. The first two fields are typically 16 bits +wide. The unused field is called `index'; it may be non-zero in +pointer-to-member-functions, which use the same layout. + +The virtual table then is an array of vtable slots. The first slot is +always the virtual type info function, the other slots are in the order +in which the virtual functions appear in the class declaration. + +If a class has base classes, it may inherit other bases' vfields. Each +class may have a primary vfield; the primary vfield of the derived class +is the primary vfield of the left-most non-virtual base class. If a +class inherits a primary vfield, any new virtual functions in the +derived class are appended to the virtual table of the primary +vfield. If there are new virtual functions in the derived class, and no +primary vfield is inherited, a new vfield is introduced which becomes +primary. The redefined virtual functions fill the vtable slots inherited +from the base; new virtual functions are put into the primary vtable in +the order of declaration. If no new virtual functions are introduced, no +primary vfield is allocated. + +In a base class that has pvbases, virtual tables are needed which are +used only in the constructor (see example above). At run-time, the +virtual tables of the base class are adjusted, to reflect the new offset +of the pvbase. The compiler knows statically what offset the pvbase has +for a complete object. At run-time, the offset of the pvbase can be +extracted from the vbase pointer, which is set in the constructor of the +complete object. These two offsets result in a delta, which is used to +adjust the deltas in the vtable (the adjustment might be different for +different vtable slots). To adjust the vtables, the compiler emits code +that creates a vtable on the stack. This vtable is initialized with the +vtable for the complete base type, and then adjusted. + +In order to call a virtual function, the compiler gets the offset field +from the vtable entry, and adds it to the this pointer. It then +indirectly calls the virtual function pointer, passing the adjusted this +pointer, and any arguments the virtual function may have. + +To implement dynamic casting, the dynamic_cast function needs typeinfos +for the complete type, and the pointer to the complete type. The +typeinfo pointer is obtained by calling the virtual typeinfo function +(which doesn't take a this parameter). The pointer to the complete +object is obtained by adding the offset of the virtual typeinfo vtable +slot, since this virtual function is always implemented in the complete +object. + +@subsection Specification of thunked vtables + +For vtable thunks, each slot only consists of a pointer to the virtual +function, which might be a thunk function. The first slot in the vtable +is an offset of the this pointer to the complete object, which is needed +as a parameter to __dynamic_cast. The second slot is the virtual +typeinfo function. All other slots are allocated with the same procedure +as in the non-thunked case. Allocation of vfields also uses the same +procedure as described above. + +If the virtual function needs an adjusted this pointer, a thunk function +is emitted. If supported by the target architecture, this is only a +half-function. Such a thunk has no stack frame; it merely adjusts the +first argument of the function, and then directly branches into the +implementation of the virtual function. If the architecture does not +support half-functions (i.e. if ASM_OUTPUT_MI_THUNK is not defined), the +compiler emits a wrapper function, which copies all arguments, adjust +the this pointer, and then calls the original function. Since objects of +non-aggregate type are passed by invisible reference, this copies only +POD arguments. The approach fails for virtual functions with a variable +number of arguments. + +In order to support the vtables needed in base constructors with +pvbases, the compiler passes an implicit __vlist argument as described +above, if the version 2 thunks are used. For version 1 thunks, the base +class constructor will fill in the vtables for the complete base class, +which will incorrectly adjust the this pointer, leading to a dynamic +error. + +@node Concept Index, , Vtables, Top @section Concept Index diff --git a/gnu/egcs/gcc/cp/init.c b/gnu/egcs/gcc/cp/init.c index 38bf2487a93..aed1fde6551 100644 --- a/gnu/egcs/gcc/cp/init.c +++ b/gnu/egcs/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/gnu/egcs/gcc/cp/method.c b/gnu/egcs/gcc/cp/method.c index d4a667bdf82..d60bfda5242 100644 --- a/gnu/egcs/gcc/cp/method.c +++ b/gnu/egcs/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/gnu/egcs/gcc/cp/rtti.c b/gnu/egcs/gcc/cp/rtti.c index e0ce5cd8666..c8c1ba95255 100644 --- a/gnu/egcs/gcc/cp/rtti.c +++ b/gnu/egcs/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/gnu/egcs/gcc/cp/search.c b/gnu/egcs/gcc/cp/search.c index 8760c6aff7d..fb99f8f8eef 100644 --- a/gnu/egcs/gcc/cp/search.c +++ b/gnu/egcs/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; diff --git a/gnu/egcs/gcc/cp/typeck2.c b/gnu/egcs/gcc/cp/typeck2.c index 6322157e624..da98203bdc0 100644 --- a/gnu/egcs/gcc/cp/typeck2.c +++ b/gnu/egcs/gcc/cp/typeck2.c @@ -344,7 +344,7 @@ my_friendly_abort (i) else ack ("Internal compiler error %d.", i); ack ("Please submit a full bug report."); - ack ("See <URL:http://www.gnu.org/software/gcc/faq.html#bugreport> for instructions."); + ack ("See %s for instructions.", GCCBUGURL); } else error ("confused by earlier errors, bailing out"); @@ -359,7 +359,7 @@ my_friendly_abort (i) error ("Internal compiler error %d.", i); error ("Please submit a full bug report."); - fatal ("See <URL:http://www.gnu.org/software/gcc/faq.html#bugreport> for instructions."); + fatal ("See %s for instructions.", GCCBUGURL); } void |