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:
commit
2213994dde
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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) \
|
||||
|
@ -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
|
||||
|
@ -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. */
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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.
|
||||
|
@ -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
225
contrib/libstdc++/sstream
Normal 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__ */
|
Loading…
Reference in New Issue
Block a user