This commit was generated by cvs2svn to compensate for changes in r60967,

which included commits to RCS files with non-trunk default branches.
This commit is contained in:
obrien 2000-05-27 02:25:28 +00:00
commit 2213994dde
21 changed files with 1571 additions and 77 deletions

View File

@ -1,3 +1,60 @@
Fri May 26 10:30:02 2000 Richard Earnshaw (rearnsha@arm.com)
* arm.md (negdi2): Add clobber of condition code register.
Wed May 24 00:25:45 2000 Alexandre Oliva <oliva@lsd.ic.unicamp.br>
2000-05-22 Richard Henderson <rth@cygnus.com>
* function.c (thread_prologue_and_epilogue_insns): Make sure
existing line number notes appear after the prologue.
2000-05-16 Franz Sirl <Franz.Sirl-kernel@lauterbach.com>
* sysv4.h (CPP_OS_LINUX_SPEC): Define __unix and __linux according
to given options.
2000-05-14 Franz Sirl <Franz.Sirl-kernel@lauterbach.com>
* rs6000/rs6000.md (nonlocal_goto_receiver): Add length attribute.
Wed Apr 12 00:42:19 2000 Jeffrey A Law (law@cygnus.com)
2000-02-19 Richard Henderson <rth@cygnus.com>
* c-typeck.c (add_pending_init): Don't abort for multiple
fields at the same offset.
(pending_init_member): Test the correct member.
Wed Apr 12 00:44:31 2000 Jeffrey A Law (law@cygnus.com)
* config/i386/freebsd-elf.h (DEFAULT_VTABLE_THUNKS): Changed to 2.
Tue Nov 9 17:14:40 1999 H.J. Lu <hjl@gnu.org>
* invoke.texi (-fvtable-thunks): Document that Linux/GNU uses
version 2 as default.
Tue Nov 9 10:16:55 1999 H.J. Lu <hjl@gnu.org>
* alpha/linux-elf.h (DEFAULT_VTABLE_THUNKS): Changed to 2.
* arm/linux-elf.h: Likewise.
* rs6000/linux.h: Likewise.
* sparc/linux.h: Likewise.
Mon Nov 8 14:41:34 1999 H.J. Lu <hjl@gnu.org>
* config/linux.h (DEFAULT_VTABLE_THUNKS): Changed to 2.
Sun May 2 08:49:27 1999 Martin von Löwis <loewis@informatik.hu-berlin.de>
* invoke.texi (-fvtable-thunks): Document numeric argument.
2000-04-11 Alexandre Oliva <oliva@lsd.ic.unicamp.br>
* config/elfos.h (SELECT_SECTION): Decide whether to use a data or
const section to output a CONSTRUCTOR based on the same conditions
used for VAR_DECLs.
Mon Apr 3 02:31:32 2000 Jeffrey A Law (law@cygnus.com)
2000-01-20 Michael Hayes <m.hayes@elec.canterbury.ac.nz>
* unroll.c (loop_iterations): Don't abort if REG_USERVAR_P set
on iteration_var.
Wed Mar 22 13:11:54 2000 David Edelsohn <edelsohn@gnu.org>
* rs6000.c (reg_or_u_cint_operand): New function.

View File

@ -5846,7 +5846,7 @@ add_pending_init (purpose, value)
p = *q;
if (tree_int_cst_lt (purpose, p->purpose))
q = &p->left;
else if (tree_int_cst_lt (p->purpose, purpose))
else if (p->purpose != purpose)
q = &p->right;
else
abort ();
@ -5860,8 +5860,7 @@ add_pending_init (purpose, value)
if (tree_int_cst_lt (DECL_FIELD_BITPOS (purpose),
DECL_FIELD_BITPOS (p->purpose)))
q = &p->left;
else if (tree_int_cst_lt (DECL_FIELD_BITPOS (p->purpose),
DECL_FIELD_BITPOS (purpose)))
else if (p->purpose != purpose)
q = &p->right;
else
abort ();
@ -6046,7 +6045,7 @@ pending_init_member (field)
{
while (p)
{
if (tree_int_cst_equal (field, p->purpose))
if (field == p->purpose)
return 1;
else if (tree_int_cst_lt (field, p->purpose))
p = p->left;

View File

@ -38,7 +38,7 @@ Boston, MA 02111-1307, USA. */
#ifndef USE_GNULIBC_1
#undef DEFAULT_VTABLE_THUNKS
#define DEFAULT_VTABLE_THUNKS 1
#define DEFAULT_VTABLE_THUNKS 2
#endif
#ifndef USE_GNULIBC_1

View File

@ -1,6 +1,6 @@
/* elfos.h -- operating system specific defines to be used when
targeting GCC for some generic ELF system
Copyright (C) 1991, 1994, 1995, 1999 Free Software Foundation, Inc.
Copyright (C) 1991, 1994, 1995, 1999, 2000 Free Software Foundation, Inc.
Based on svr4.h contributed by Ron Guilmette (rfg@netcom.com).
This file is part of GNU CC.
@ -426,7 +426,8 @@ do { \
else \
data_section (); \
} \
else if (TREE_CODE (DECL) == VAR_DECL) \
else if (TREE_CODE (DECL) == VAR_DECL \
|| TREE_CODE (DECL) == CONSTRUCTOR) \
{ \
if ((flag_pic && RELOC) \
|| !TREE_READONLY (DECL) || TREE_SIDE_EFFECTS (DECL) \

View File

@ -89,7 +89,7 @@ Boston, MA 02111-1307, USA. */
#ifndef USE_GNULIBC_1
#undef DEFAULT_VTABLE_THUNKS
#define DEFAULT_VTABLE_THUNKS 1
#define DEFAULT_VTABLE_THUNKS 2
#endif
#undef LIB_SPEC

View File

@ -37,7 +37,7 @@ Boston, MA 02111-1307, USA. */
#ifndef USE_GNULIBC_1
#undef DEFAULT_VTABLE_THUNKS
#define DEFAULT_VTABLE_THUNKS 1
#define DEFAULT_VTABLE_THUNKS 2
#endif
/* Use stabs instead of DWARF debug format. */

View File

@ -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.

View File

@ -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);
}

View File

@ -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

View File

@ -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));

View File

@ -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

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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
build_destructor_name (type)
tree type;
get_vlist_vtable_id (base, vbase)
tree base, vbase;
{
return build_overload_with_type (get_identifier (DESTRUCTOR_DECL_PREFIX),
type);
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, has_vlist)
tree type;
int has_vlist;
{
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),
@ -2177,6 +2239,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. */
@ -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);
}

View File

@ -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));
}

View File

@ -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;

View File

@ -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;

View File

@ -3682,10 +3682,14 @@ loop_iterations (loop_start, loop_end, loop_info)
return 0;
}
/* The only new registers that care created before loop iterations are
givs made from biv increments, so this should never occur. */
/* The only new registers that are created before loop iterations
are givs made from biv increments or registers created by
load_mems. In the latter case, it is possible that try_copy_prop
will propagate a new pseudo into the old iteration register but
this will be marked by having the REG_USERVAR_P bit set. */
if ((unsigned) REGNO (iteration_var) >= reg_iv_type->num_elements)
if ((unsigned) REGNO (iteration_var) >= reg_iv_type->num_elements
&& ! REG_USERVAR_P (iteration_var))
abort ();
iteration_info (iteration_var, &initial_value, &increment,

View File

@ -1,3 +1,8 @@
2000-04-24 Magnus Fromreide <magfr@lysator.liu.se>
* sstream: New file.
* Makefile.in (HEADERS): Add it.
2000-03-12 Gabriel Dos Reis <dosreis@cmla.ens-cachan.fr>
* std/bastring.h (basic_string<>::push_back): Define.

View File

@ -28,7 +28,8 @@ HEADERS= cassert cctype cerrno cfloat ciso646 climits clocale cmath complex \
cwchar cwctype string stdexcept \
algorithm deque functional hash_map hash_set iterator list map \
memory numeric pthread_alloc queue rope set slist stack utility \
vector fstream iomanip iostream strstream iosfwd bitset valarray
vector fstream iomanip iostream strstream iosfwd bitset valarray \
sstream
ARLIB = libstdc++.a.$(VERSION)
ARLINK = libstdc++.a

225
contrib/libstdc++/sstream Normal file
View File

@ -0,0 +1,225 @@
/* This is part of libio/iostream, providing -*- C++ -*- input/output.
Copyright (C) 2000 Free Software Foundation
This file is part of the GNU IO Library. This library is free
software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option)
any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this library; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
As a special exception, if you link this library with files
compiled with a GNU compiler to produce an executable, this does not cause
the resulting executable to be covered by the GNU General Public License.
This exception does not however invalidate any other reasons why
the executable file might be covered by the GNU General Public License. */
/* Written by Magnus Fromreide (magfr@lysator.liu.se). */
#ifndef __SSTREAM__
#define __SSTREAM__
#include <string>
#include <iostream.h>
#include <streambuf.h>
namespace std
{
class stringbuf : public streambuf
{
public:
typedef char char_type;
typedef int int_type;
typedef streampos pos_type;
typedef streamoff off_type;
explicit stringbuf(int which=ios::in|ios::out) :
streambuf(which), buf(), mode(static_cast<ios::open_mode>(which)),
rpos(0), bufsize(1)
{ }
explicit stringbuf(const std::string &s, int which=ios::in|ios::out) :
streambuf(which), buf(s), mode(static_cast<ios::open_mode>(which)),
bufsize(1)
{
if(mode & ios::in)
{
setg(&defbuf, &defbuf + bufsize, &defbuf + bufsize);
}
if(mode & ios::out)
{
setp(&defbuf, &defbuf + bufsize);
}
rpos = (mode & ios::ate ? s.size() : 0);
}
std::string str() const
{
const_cast<stringbuf*>(this)->sync(); // Sigh, really ugly hack
return buf;
};
void str(const std::string& s)
{
buf = s;
if(mode & ios::in)
{
gbump(egptr() - gptr());
}
if(mode & ios::out)
{
pbump(pbase() - pptr());
}
rpos = (mode & ios::ate ? s.size() : 0);
}
protected:
inline virtual int sync();
inline virtual int overflow(int = EOF);
inline virtual int underflow();
private:
std::string buf;
ios::open_mode mode;
std::string::size_type rpos;
streamsize bufsize;
char defbuf;
};
class stringstreambase : virtual public ios {
protected:
stringbuf __my_sb;
public:
std::string str() const
{
return dynamic_cast<stringbuf*>(_strbuf)->str();
}
void str(const std::string& s)
{
clear();
dynamic_cast<stringbuf*>(_strbuf)->str(s);
}
stringbuf* rdbuf()
{
return &__my_sb;
}
protected:
stringstreambase(int which) :
__my_sb(which)
{
init (&__my_sb);
}
stringstreambase(const std::string& s, int which) :
__my_sb(s, which)
{
init (&__my_sb);
}
};
class istringstream : public stringstreambase, public istream {
public:
istringstream(int which=ios::in) :
stringstreambase(which)
{ }
istringstream(const std::string& s, int which=ios::in) :
stringstreambase(s, which)
{ }
};
class ostringstream : public stringstreambase, public ostream {
public:
ostringstream(int which=ios::out) :
stringstreambase(which)
{ }
ostringstream(const std::string& s, int which=ios::out) :
stringstreambase(s, which)
{ }
};
class stringstream : public stringstreambase, public iostream {
public:
stringstream(int which=ios::in|ios::out) :
stringstreambase(which)
{ }
stringstream(const std::string &s, int which=ios::in|ios::out) :
stringstreambase(s, which)
{ }
};
}
inline int std::stringbuf::sync()
{
if((mode & ios::out) == 0)
return EOF;
streamsize n = pptr() - pbase();
if(n)
{
buf.replace(rpos, std::string::npos, pbase(), n);
if(buf.size() - rpos != n)
return EOF;
rpos += n;
pbump(-n);
gbump(egptr() - gptr());
}
return 0;
}
inline int std::stringbuf::overflow(int ch)
{
if((mode & ios::out) == 0)
return EOF;
streamsize n = pptr() - pbase();
if(n && sync())
return EOF;
if(ch != EOF)
{
std::string::size_type oldSize = buf.size();
buf.replace(rpos, std::string::npos, ch);
if(buf.size() - oldSize != 1)
return EOF;
++rpos;
}
return 0;
}
inline int std::stringbuf::underflow()
{
sync();
if((mode & ios::in) == 0)
{
return EOF;
}
if(rpos >= buf.size())
{
return EOF;
}
std::string::size_type n = egptr() - eback();
std::string::size_type s;
s = buf.copy(eback(), n, rpos);
pbump(pbase() - pptr());
gbump(eback() - gptr());
int res = (0377 & buf[rpos]);
rpos += s;
return res;
}
#endif /* not __STRSTREAM__ */