Finish implementation of VTTs.

* cp-tree.h (cp_tree_index): Add CPTI_VTT_PARM_TYPE and
	CPTI_VTT_PARM_IDENTIFIER.
	(vtt_parm_identifier): New macro.
	(vtt_parm_type): Likewise.
	(BINFO_SUBVTT_INDEX): Likewise.
	(BINFO_VPTR_INDEX): Likewise.
	(struct lang_decl): Add vtt_parm.
	(DECL_VTT_PARM): New macro.
	(DECL_USE_VTT_PARM): Likewise.
	(DECL_NEEDS_VTT_PARM_P): Likewise.
	(get_vtt_name): Declare.
	(build_artifical_parm): Likewise.
	(fixup_all_virtual_upcast_offsets): Likewise.
	(expand_indirect_vtbls_init): Remove.
	* call.c (build_new_method_call): Pass the vtt to subobject
	constructors and destructors.
	* class.c (get_vtt_name): Give it external linkage.
	(build_clone): Handle the magic VTT parameters for clones.
	(clone_function_decl): Fix typo in comment.
	(build_vtt): Keep track of the indices in the VTTs where various
	entities are stored.
	(build_vtt_inits): Likewise.
	(dfs_build_vtt_inits): Likewise.
	(build_ctor_vtbl_group): Tweak type of construction vtables.
	(dfs_accumulate_vtbl_inits): Build vtables for all bases, even
	primary bases, when building construction vtables.
	* decl.c (duplicate_decls): Handle DECL_VTT_PARM.
	(initialize_predefined_identifiers): Add vtt_parm_identifier.
	(init_decl_processing): Initialize vtt_parm_type.
	(grokfndecl): Use DECL_OVERLOADED_OPERATOR_P.
	(lang_mark_tree): Make vtt_parm.
	* decl2.c (build_artificial_parm): New function.
	(maybe_retrofit_in_chrg): Use it.  Add VTT parameters.
	(grokclassfn): Use build_artificial_parm.
	* init.c (initialize_vtbl_ptrs): Call
	fixup_all_virtual_upcast_offsets directly.
	(perform_member_init): Use the complete subobject destructor for
	member cleanups.
	(build_vtbl_address): New function.
	(expand_virtual_init): Handle VTTs.
	* optimize (maybe_clone_body): Likewise.
	* search.c (fixup_all_virtual_upcast_offsets): Give it external
	linkage.
	(expand_indirect_vtbls_init): Remove.
	* semantics.c (setup_vtbl_ptr): Fix typos in comment.
	* tree.c (make_binfo): Make them bigger.

From-SVN: r34177
This commit is contained in:
Mark Mitchell 2000-05-25 23:27:18 +00:00 committed by Mark Mitchell
parent a0ee3b8335
commit 3ec6bad360
13 changed files with 401 additions and 68 deletions

View File

@ -1,3 +1,53 @@
2000-05-25 Mark Mitchell <mark@codesourcery.com>
Finish implementation of VTTs.
* cp-tree.h (cp_tree_index): Add CPTI_VTT_PARM_TYPE and
CPTI_VTT_PARM_IDENTIFIER.
(vtt_parm_identifier): New macro.
(vtt_parm_type): Likewise.
(BINFO_SUBVTT_INDEX): Likewise.
(BINFO_VPTR_INDEX): Likewise.
(struct lang_decl): Add vtt_parm.
(DECL_VTT_PARM): New macro.
(DECL_USE_VTT_PARM): Likewise.
(DECL_NEEDS_VTT_PARM_P): Likewise.
(get_vtt_name): Declare.
(build_artifical_parm): Likewise.
(fixup_all_virtual_upcast_offsets): Likewise.
(expand_indirect_vtbls_init): Remove.
* call.c (build_new_method_call): Pass the vtt to subobject
constructors and destructors.
* class.c (get_vtt_name): Give it external linkage.
(build_clone): Handle the magic VTT parameters for clones.
(clone_function_decl): Fix typo in comment.
(build_vtt): Keep track of the indices in the VTTs where various
entities are stored.
(build_vtt_inits): Likewise.
(dfs_build_vtt_inits): Likewise.
(build_ctor_vtbl_group): Tweak type of construction vtables.
(dfs_accumulate_vtbl_inits): Build vtables for all bases, even
primary bases, when building construction vtables.
* decl.c (duplicate_decls): Handle DECL_VTT_PARM.
(initialize_predefined_identifiers): Add vtt_parm_identifier.
(init_decl_processing): Initialize vtt_parm_type.
(grokfndecl): Use DECL_OVERLOADED_OPERATOR_P.
(lang_mark_tree): Make vtt_parm.
* decl2.c (build_artificial_parm): New function.
(maybe_retrofit_in_chrg): Use it. Add VTT parameters.
(grokclassfn): Use build_artificial_parm.
* init.c (initialize_vtbl_ptrs): Call
fixup_all_virtual_upcast_offsets directly.
(perform_member_init): Use the complete subobject destructor for
member cleanups.
(build_vtbl_address): New function.
(expand_virtual_init): Handle VTTs.
* optimize (maybe_clone_body): Likewise.
* search.c (fixup_all_virtual_upcast_offsets): Give it external
linkage.
(expand_indirect_vtbls_init): Remove.
* semantics.c (setup_vtbl_ptr): Fix typos in comment.
* tree.c (make_binfo): Make them bigger.
2000-05-25 Nathan Sidwell <nathan@codesourcery.com> 2000-05-25 Nathan Sidwell <nathan@codesourcery.com>
* inc/cxxabi.h (__pbase_type_info): Define, based on * inc/cxxabi.h (__pbase_type_info): Define, based on

View File

@ -4321,6 +4321,32 @@ build_new_method_call (instance, name, args, basetype_path, flags)
old ABI. */ old ABI. */
name = constructor_p ? ctor_identifier : dtor_identifier; name = constructor_p ? ctor_identifier : dtor_identifier;
} }
/* If we're call a subobject constructor or destructor for a
subobject that uses virtual base classes, then we need to
pass down a pointer to a VTT for the subobject. */
else if ((name == base_ctor_identifier
|| name == base_dtor_identifier)
&& TYPE_USES_VIRTUAL_BASECLASSES (basetype))
{
tree vtt;
tree sub_vtt;
/* If the current function is a complete object constructor
or destructor, then we fetch the VTT directly.
Otherwise, we look it up using the VTT we were given. */
vtt = IDENTIFIER_GLOBAL_VALUE (get_vtt_name (current_class_type));
vtt = build_unary_op (ADDR_EXPR, vtt, /*noconvert=*/1);
vtt = build (COND_EXPR, TREE_TYPE (vtt),
DECL_USE_VTT_PARM (current_function_decl),
DECL_VTT_PARM (current_function_decl),
vtt);
sub_vtt = build (PLUS_EXPR, TREE_TYPE (vtt), vtt,
BINFO_SUBVTT_INDEX (basetype_path));
sub_vtt = build_indirect_ref (sub_vtt, NULL);
args = tree_cons (NULL_TREE, sub_vtt, args);
}
} }
else else
pretty_name = name; pretty_name = name;

View File

@ -181,7 +181,7 @@ static void update_vtable_entry_for_fn PARAMS ((tree, tree, tree, tree *));
static tree copy_virtuals PARAMS ((tree)); static tree copy_virtuals PARAMS ((tree));
static void build_ctor_vtbl_group PARAMS ((tree, tree)); static void build_ctor_vtbl_group PARAMS ((tree, tree));
static void build_vtt PARAMS ((tree)); static void build_vtt PARAMS ((tree));
static tree *build_vtt_inits PARAMS ((tree, tree, tree *)); static tree *build_vtt_inits PARAMS ((tree, tree, tree *, tree *));
static tree dfs_build_vtt_inits PARAMS ((tree, void *)); static tree dfs_build_vtt_inits PARAMS ((tree, void *));
static tree dfs_fixup_binfo_vtbls PARAMS ((tree, void *)); static tree dfs_fixup_binfo_vtbls PARAMS ((tree, void *));
@ -635,7 +635,7 @@ get_vtable_name (type)
/* Return an IDENTIFIER_NODE for the name of the virtual table table /* Return an IDENTIFIER_NODE for the name of the virtual table table
for TYPE. */ for TYPE. */
static tree tree
get_vtt_name (type) get_vtt_name (type)
tree type; tree type;
{ {
@ -3957,6 +3957,8 @@ build_clone (fn, name)
DECL_PENDING_INLINE_P (clone) = 0; DECL_PENDING_INLINE_P (clone) = 0;
/* And it hasn't yet been deferred. */ /* And it hasn't yet been deferred. */
DECL_DEFERRED_FN (clone) = 0; DECL_DEFERRED_FN (clone) = 0;
/* There's no magic VTT parameter in the clone. */
DECL_VTT_PARM (clone) = NULL_TREE;
/* The base-class destructor is not virtual. */ /* The base-class destructor is not virtual. */
if (name == base_dtor_identifier) if (name == base_dtor_identifier)
@ -3981,6 +3983,10 @@ build_clone (fn, name)
parmtypes = TREE_CHAIN (parmtypes); parmtypes = TREE_CHAIN (parmtypes);
/* Skip the in-charge parameter. */ /* Skip the in-charge parameter. */
parmtypes = TREE_CHAIN (parmtypes); parmtypes = TREE_CHAIN (parmtypes);
/* If this is subobject constructor or destructor, add the vtt
parameter. */
if (DECL_NEEDS_VTT_PARM_P (clone))
parmtypes = hash_tree_chain (vtt_parm_type, parmtypes);
TREE_TYPE (clone) TREE_TYPE (clone)
= build_cplus_method_type (basetype, = build_cplus_method_type (basetype,
TREE_TYPE (TREE_TYPE (clone)), TREE_TYPE (TREE_TYPE (clone)),
@ -4002,6 +4008,18 @@ build_clone (fn, name)
= TREE_CHAIN (TREE_CHAIN (DECL_ARGUMENTS (clone))); = TREE_CHAIN (TREE_CHAIN (DECL_ARGUMENTS (clone)));
DECL_HAS_IN_CHARGE_PARM_P (clone) = 0; DECL_HAS_IN_CHARGE_PARM_P (clone) = 0;
} }
/* Add the VTT parameter. */
if (DECL_NEEDS_VTT_PARM_P (clone))
{
tree parm;
parm = build_artificial_parm (vtt_parm_identifier,
vtt_parm_type);
TREE_CHAIN (parm) = TREE_CHAIN (DECL_ARGUMENTS (clone));
TREE_CHAIN (DECL_ARGUMENTS (clone)) = parm;
}
for (parms = DECL_ARGUMENTS (clone); parms; parms = TREE_CHAIN (parms)) for (parms = DECL_ARGUMENTS (clone); parms; parms = TREE_CHAIN (parms))
{ {
DECL_CONTEXT (parms) = clone; DECL_CONTEXT (parms) = clone;
@ -4063,7 +4081,7 @@ clone_function_decl (fn, update_method_vec_p)
{ {
my_friendly_assert (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (fn), 20000411); my_friendly_assert (DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (fn), 20000411);
/* For each destructor, we need two variants: an in-charge /* For each destructor, we need three variants: an in-charge
version, a not-in-charge version, and an in-charge deleting version, a not-in-charge version, and an in-charge deleting
version. We clone the deleting version first because that version. We clone the deleting version first because that
means it will go second on the TYPE_METHODS list -- and that means it will go second on the TYPE_METHODS list -- and that
@ -6474,6 +6492,7 @@ build_vtt (t)
tree inits; tree inits;
tree type; tree type;
tree vtt; tree vtt;
tree index;
/* Under the old ABI, we don't use VTTs. */ /* Under the old ABI, we don't use VTTs. */
if (!flag_new_abi) if (!flag_new_abi)
@ -6481,7 +6500,8 @@ build_vtt (t)
/* Build up the initializers for the VTT. */ /* Build up the initializers for the VTT. */
inits = NULL_TREE; inits = NULL_TREE;
build_vtt_inits (TYPE_BINFO (t), t, &inits); index = size_zero_node;
build_vtt_inits (TYPE_BINFO (t), t, &inits, &index);
/* If we didn't need a VTT, we're done. */ /* If we didn't need a VTT, we're done. */
if (!inits) if (!inits)
@ -6499,13 +6519,15 @@ build_vtt (t)
/* Recursively build the VTT-initializer for BINFO (which is in the /* Recursively build the VTT-initializer for BINFO (which is in the
hierarchy dominated by T). INITS points to the end of the hierarchy dominated by T). INITS points to the end of the
initializer list to date. */ initializer list to date. INDEX is the VTT index where the next
element will be placed. */
static tree * static tree *
build_vtt_inits (binfo, t, inits) build_vtt_inits (binfo, t, inits, index)
tree binfo; tree binfo;
tree t; tree t;
tree *inits; tree *inits;
tree *index;
{ {
int i; int i;
tree b; tree b;
@ -6521,7 +6543,12 @@ build_vtt_inits (binfo, t, inits)
VTT. */ VTT. */
ctor_vtbl_p = !same_type_p (TREE_TYPE (binfo), t); ctor_vtbl_p = !same_type_p (TREE_TYPE (binfo), t);
if (ctor_vtbl_p) if (ctor_vtbl_p)
build_ctor_vtbl_group (binfo, t); {
build_ctor_vtbl_group (binfo, t);
/* Record the offset in the VTT where this sub-VTT can be found. */
BINFO_SUBVTT_INDEX (binfo) = *index;
}
/* Add the address of the primary vtable for the complete object. */ /* Add the address of the primary vtable for the complete object. */
init = BINFO_VTABLE (binfo); init = BINFO_VTABLE (binfo);
@ -6529,20 +6556,24 @@ build_vtt_inits (binfo, t, inits)
init = TREE_PURPOSE (init); init = TREE_PURPOSE (init);
*inits = build_tree_list (NULL_TREE, init); *inits = build_tree_list (NULL_TREE, init);
inits = &TREE_CHAIN (*inits); inits = &TREE_CHAIN (*inits);
BINFO_VPTR_INDEX (binfo) = *index;
*index = size_binop (PLUS_EXPR, *index, TYPE_SIZE_UNIT (ptr_type_node));
/* Recursively add the secondary VTTs for non-virtual bases. */ /* Recursively add the secondary VTTs for non-virtual bases. */
for (i = 0; i < BINFO_N_BASETYPES (binfo); ++i) for (i = 0; i < BINFO_N_BASETYPES (binfo); ++i)
{ {
b = BINFO_BASETYPE (binfo, i); b = BINFO_BASETYPE (binfo, i);
if (!TREE_VIA_VIRTUAL (b)) if (!TREE_VIA_VIRTUAL (b))
inits = build_vtt_inits (BINFO_BASETYPE (binfo, i), t, inits); inits = build_vtt_inits (BINFO_BASETYPE (binfo, i), t, inits,
index);
} }
/* Add secondary virtual pointers for all subobjects of BINFO with /* Add secondary virtual pointers for all subobjects of BINFO with
either virtual bases or virtual functions overridden along a either virtual bases or virtual functions overridden along a
virtual path between the declaration and D, except subobjects virtual path between the declaration and D, except subobjects
that are non-virtual primary bases. */ that are non-virtual primary bases. */
secondary_vptrs = build_tree_list (BINFO_TYPE (binfo), NULL_TREE); secondary_vptrs = build_tree_list (BINFO_TYPE (binfo), NULL_TREE);
TREE_TYPE (secondary_vptrs) = *index;
dfs_walk_real (binfo, dfs_walk_real (binfo,
dfs_build_vtt_inits, dfs_build_vtt_inits,
NULL, NULL,
@ -6550,6 +6581,7 @@ build_vtt_inits (binfo, t, inits)
secondary_vptrs); secondary_vptrs);
dfs_walk (binfo, dfs_fixup_binfo_vtbls, dfs_marked_real_bases_queue_p, dfs_walk (binfo, dfs_fixup_binfo_vtbls, dfs_marked_real_bases_queue_p,
BINFO_TYPE (binfo)); BINFO_TYPE (binfo));
*index = TREE_TYPE (secondary_vptrs);
/* The secondary vptrs come back in reverse order. After we reverse /* The secondary vptrs come back in reverse order. After we reverse
them, and add the INITS, the last init will be the first element them, and add the INITS, the last init will be the first element
@ -6571,7 +6603,7 @@ build_vtt_inits (binfo, t, inits)
continue; continue;
vbase = binfo_for_vbase (BINFO_TYPE (b), t); vbase = binfo_for_vbase (BINFO_TYPE (b), t);
inits = build_vtt_inits (vbase, t, inits); inits = build_vtt_inits (vbase, t, inits, index);
} }
return inits; return inits;
@ -6587,6 +6619,7 @@ dfs_build_vtt_inits (binfo, data)
tree l; tree l;
tree t; tree t;
tree init; tree init;
tree index;
l = (tree) data; l = (tree) data;
t = TREE_PURPOSE (l); t = TREE_PURPOSE (l);
@ -6612,13 +6645,18 @@ dfs_build_vtt_inits (binfo, data)
/* FIXME: Implement this. */ /* FIXME: Implement this. */
; ;
/* Add the initializer for this secondary vptr. */ /* Record the index where this secondary vptr can be found. */
index = TREE_TYPE (l);
BINFO_VPTR_INDEX (binfo) = index;
TREE_TYPE (l) = size_binop (PLUS_EXPR, index,
TYPE_SIZE_UNIT (ptr_type_node));
/* Add the initializer for the secondary vptr itself. */
init = BINFO_VTABLE (binfo); init = BINFO_VTABLE (binfo);
if (TREE_CODE (init) == TREE_LIST) if (TREE_CODE (init) == TREE_LIST)
init = TREE_PURPOSE (init); init = TREE_PURPOSE (init);
TREE_VALUE (l) = tree_cons (NULL_TREE, init, TREE_VALUE (l)); TREE_VALUE (l) = tree_cons (NULL_TREE, init, TREE_VALUE (l));
return NULL_TREE; return NULL_TREE;
} }
@ -6665,7 +6703,7 @@ build_ctor_vtbl_group (binfo, t)
/* Build a version of VTBL (with the wrong type) for use in /* Build a version of VTBL (with the wrong type) for use in
constructing the addresses of secondary vtables in the constructing the addresses of secondary vtables in the
construction vtable group. */ construction vtable group. */
vtbl = build_vtable (BINFO_TYPE (binfo), id, vtable_entry_type); vtbl = build_vtable (BINFO_TYPE (binfo), id, ptr_type_node);
list = build_tree_list (vtbl, NULL_TREE); list = build_tree_list (vtbl, NULL_TREE);
accumulate_vtbl_inits (binfo, TYPE_BINFO (TREE_TYPE (binfo)), accumulate_vtbl_inits (binfo, TYPE_BINFO (TREE_TYPE (binfo)),
binfo, t, list); binfo, t, list);
@ -6762,7 +6800,7 @@ dfs_accumulate_vtbl_inits (binfo, orig_binfo, rtti_binfo, t, l)
if (BINFO_NEW_VTABLE_MARKED (binfo, t) if (BINFO_NEW_VTABLE_MARKED (binfo, t)
/* We need a new vtable, even for a primary base, when we're /* We need a new vtable, even for a primary base, when we're
building a construction vtable. */ building a construction vtable. */
|| (ctor_vtbl_p && orig_binfo == rtti_binfo)) || (ctor_vtbl_p && CLASSTYPE_VFIELDS (BINFO_TYPE (binfo))))
{ {
tree vtbl; tree vtbl;
tree index; tree index;

View File

@ -530,6 +530,7 @@ enum cp_tree_index
CPTI_DELTA_TYPE, CPTI_DELTA_TYPE,
CPTI_VTABLE_INDEX_TYPE, CPTI_VTABLE_INDEX_TYPE,
CPTI_CLEANUP_TYPE, CPTI_CLEANUP_TYPE,
CPTI_VTT_PARM_TYPE,
CPTI_TI_DESC_TYPE, CPTI_TI_DESC_TYPE,
CPTI_BLTN_DESC_TYPE, CPTI_BLTN_DESC_TYPE,
@ -578,6 +579,7 @@ enum cp_tree_index
CPTI_DELTA2_IDENTIFIER, CPTI_DELTA2_IDENTIFIER,
CPTI_DELTA_IDENTIFIER, CPTI_DELTA_IDENTIFIER,
CPTI_IN_CHARGE_IDENTIFIER, CPTI_IN_CHARGE_IDENTIFIER,
CPTI_VTT_PARM_IDENTIFIER,
CPTI_INDEX_IDENTIFIER, CPTI_INDEX_IDENTIFIER,
CPTI_NELTS_IDENTIFIER, CPTI_NELTS_IDENTIFIER,
CPTI_THIS_IDENTIFIER, CPTI_THIS_IDENTIFIER,
@ -690,6 +692,11 @@ extern tree cp_global_trees[CPTI_MAX];
#define delta2_identifier cp_global_trees[CPTI_DELTA2_IDENTIFIER] #define delta2_identifier cp_global_trees[CPTI_DELTA2_IDENTIFIER]
#define delta_identifier cp_global_trees[CPTI_DELTA_IDENTIFIER] #define delta_identifier cp_global_trees[CPTI_DELTA_IDENTIFIER]
#define in_charge_identifier cp_global_trees[CPTI_IN_CHARGE_IDENTIFIER] #define in_charge_identifier cp_global_trees[CPTI_IN_CHARGE_IDENTIFIER]
/* The name of the parameter that contains a pointer to the VTT to use
for this subobject constructor or destructor. */
#define vtt_parm_identifier cp_global_trees[CPTI_VTT_PARM_IDENTIFIER]
#define index_identifier cp_global_trees[CPTI_INDEX_IDENTIFIER] #define index_identifier cp_global_trees[CPTI_INDEX_IDENTIFIER]
#define nelts_identifier cp_global_trees[CPTI_NELTS_IDENTIFIER] #define nelts_identifier cp_global_trees[CPTI_NELTS_IDENTIFIER]
#define this_identifier cp_global_trees[CPTI_THIS_IDENTIFIER] #define this_identifier cp_global_trees[CPTI_THIS_IDENTIFIER]
@ -731,6 +738,10 @@ extern tree cp_global_trees[CPTI_MAX];
/* The type of a destructor. */ /* The type of a destructor. */
#define cleanup_type cp_global_trees[CPTI_CLEANUP_TYPE] #define cleanup_type cp_global_trees[CPTI_CLEANUP_TYPE]
/* The type of the vtt parameter passed to subobject constructors and
destructors. */
#define vtt_parm_type cp_global_trees[CPTI_VTT_PARM_TYPE]
/* Global state. */ /* Global state. */
struct stmt_tree { struct stmt_tree {
@ -1755,6 +1766,14 @@ struct lang_type
is primary *somewhere* in the hierarchy. */ is primary *somewhere* in the hierarchy. */
#define BINFO_VBASE_PRIMARY_P(NODE) TREE_LANG_FLAG_6 (NODE) #define BINFO_VBASE_PRIMARY_P(NODE) TREE_LANG_FLAG_6 (NODE)
/* The index in the VTT where this subobject's sub-VTT can be found.
NULL_TREE if there is no sub-VTT. */
#define BINFO_SUBVTT_INDEX(NODE) TREE_VEC_ELT ((NODE), 8)
/* The index in the VTT where the vptr for this subobject can be
found. NULL_TREE if there is no secondary vptr in the VTT. */
#define BINFO_VPTR_INDEX(NODE) TREE_VEC_ELT ((NODE), 9)
/* Used by various search routines. */ /* Used by various search routines. */
#define IDENTIFIER_MARKED(NODE) TREE_LANG_FLAG_0 (NODE) #define IDENTIFIER_MARKED(NODE) TREE_LANG_FLAG_0 (NODE)
@ -1884,6 +1903,9 @@ struct lang_decl
/* In a FUNCTION_DECL, this is DECL_CLONED_FUNCTION. */ /* In a FUNCTION_DECL, this is DECL_CLONED_FUNCTION. */
tree cloned_function; tree cloned_function;
/* In a FUNCTION_DECL, this is VTT_PARM. */
tree vtt_parm;
union union
{ {
tree sorted_fields; tree sorted_fields;
@ -1972,6 +1994,25 @@ struct lang_decl
#define DECL_CLONED_FUNCTION(NODE) \ #define DECL_CLONED_FUNCTION(NODE) \
(DECL_LANG_SPECIFIC (NODE)->cloned_function) (DECL_LANG_SPECIFIC (NODE)->cloned_function)
/* In a maybe-in-charge constructor or destructor, this is the VTT
parameter. It's not actually on the DECL_ARGUMENTS list. */
#define DECL_VTT_PARM(NODE) \
(DECL_LANG_SPECIFIC (NODE)->vtt_parm)
/* If there's a DECL_VTT_PARM, this is a magic variable that indicates
whether or not the VTT parm should be used. In a subobject
constructor, `true' is substituted for this value; in a complete
object constructor, `false' is substituted instead. */
#define DECL_USE_VTT_PARM(NODE) \
(TREE_CHAIN (DECL_VTT_PARM (NODE)))
/* Non-zero if NODE is a FUNCTION_DECL for which a VTT parameter is
required. */
#define DECL_NEEDS_VTT_PARM_P(NODE) \
(TYPE_USES_VIRTUAL_BASECLASSES (DECL_CONTEXT (NODE)) \
&& (DECL_BASE_CONSTRUCTOR_P (NODE) \
|| DECL_BASE_DESTRUCTOR_P (NODE)))
/* Non-zero if NODE is a user-defined conversion operator. */ /* Non-zero if NODE is a user-defined conversion operator. */
#define DECL_CONV_FN_P(NODE) \ #define DECL_CONV_FN_P(NODE) \
(IDENTIFIER_TYPENAME_P (DECL_NAME (NODE))) (IDENTIFIER_TYPENAME_P (DECL_NAME (NODE)))
@ -3820,6 +3861,7 @@ extern void maybe_note_name_used_in_class PARAMS ((tree, tree));
extern void note_name_declared_in_class PARAMS ((tree, tree)); extern void note_name_declared_in_class PARAMS ((tree, tree));
extern tree get_vtbl_decl_for_binfo PARAMS ((tree)); extern tree get_vtbl_decl_for_binfo PARAMS ((tree));
extern tree in_charge_arg_for_name PARAMS ((tree)); extern tree in_charge_arg_for_name PARAMS ((tree));
extern tree get_vtt_name PARAMS ((tree));
/* in cvt.c */ /* in cvt.c */
extern tree convert_to_reference PARAMS ((tree, tree, int, int, tree)); extern tree convert_to_reference PARAMS ((tree, tree, int, int, tree));
@ -4054,6 +4096,7 @@ extern void mark_used PARAMS ((tree));
extern tree handle_class_head PARAMS ((tree, tree, tree)); extern tree handle_class_head PARAMS ((tree, tree, tree));
extern tree lookup_arg_dependent PARAMS ((tree, tree, tree)); extern tree lookup_arg_dependent PARAMS ((tree, tree, tree));
extern void finish_static_data_member_decl PARAMS ((tree, tree, tree, int)); extern void finish_static_data_member_decl PARAMS ((tree, tree, tree, int));
extern tree build_artificial_parm PARAMS ((tree, tree));
/* in parse.y */ /* in parse.y */
extern void cp_parse_init PARAMS ((void)); extern void cp_parse_init PARAMS ((void));
@ -4303,7 +4346,6 @@ extern tree lookup_nested_tag PARAMS ((tree, tree));
extern tree get_matching_virtual PARAMS ((tree, tree, int)); extern tree get_matching_virtual PARAMS ((tree, tree, int));
extern void get_pure_virtuals PARAMS ((tree)); extern void get_pure_virtuals PARAMS ((tree));
extern tree init_vbase_pointers PARAMS ((tree, tree)); extern tree init_vbase_pointers PARAMS ((tree, tree));
extern void expand_indirect_vtbls_init PARAMS ((tree));
extern void get_vbase_types PARAMS ((tree)); extern void get_vbase_types PARAMS ((tree));
extern void maybe_suppress_debug_info PARAMS ((tree)); extern void maybe_suppress_debug_info PARAMS ((tree));
extern void note_debug_info_needed PARAMS ((tree)); extern void note_debug_info_needed PARAMS ((tree));
@ -4340,6 +4382,7 @@ extern tree unmarked_vtable_pathp PARAMS ((tree, void *));
extern tree convert_pointer_to_vbase PARAMS ((tree, tree)); extern tree convert_pointer_to_vbase PARAMS ((tree, tree));
extern tree find_vbase_instance PARAMS ((tree, tree)); extern tree find_vbase_instance PARAMS ((tree, tree));
extern tree binfo_for_vbase PARAMS ((tree, tree)); extern tree binfo_for_vbase PARAMS ((tree, tree));
extern void fixup_all_virtual_upcast_offsets PARAMS ((tree));
/* in semantics.c */ /* in semantics.c */
extern void finish_expr_stmt PARAMS ((tree)); extern void finish_expr_stmt PARAMS ((tree));

View File

@ -3369,6 +3369,7 @@ duplicate_decls (newdecl, olddecl)
DECL_VIRTUAL_P (newdecl) |= DECL_VIRTUAL_P (olddecl); DECL_VIRTUAL_P (newdecl) |= DECL_VIRTUAL_P (olddecl);
DECL_NEEDS_FINAL_OVERRIDER_P (newdecl) |= DECL_NEEDS_FINAL_OVERRIDER_P (olddecl); DECL_NEEDS_FINAL_OVERRIDER_P (newdecl) |= DECL_NEEDS_FINAL_OVERRIDER_P (olddecl);
DECL_THIS_STATIC (newdecl) |= DECL_THIS_STATIC (olddecl); DECL_THIS_STATIC (newdecl) |= DECL_THIS_STATIC (olddecl);
DECL_VTT_PARM (newdecl) = DECL_VTT_PARM (olddecl);
new_defines_function = DECL_INITIAL (newdecl) != NULL_TREE; new_defines_function = DECL_INITIAL (newdecl) != NULL_TREE;
/* Optionally warn about more than one declaration for the same /* Optionally warn about more than one declaration for the same
@ -6074,6 +6075,7 @@ initialize_predefined_identifiers ()
{ "__pfn_or_delta2", &pfn_or_delta2_identifier, 0 }, { "__pfn_or_delta2", &pfn_or_delta2_identifier, 0 },
{ "_vptr", &vptr_identifier, 0 }, { "_vptr", &vptr_identifier, 0 },
{ "__cp_push_exception", &cp_push_exception_identifier, 0 }, { "__cp_push_exception", &cp_push_exception_identifier, 0 },
{ "__vtt_parm", &vtt_parm_identifier, 0 },
{ NULL, NULL, 0 } { NULL, NULL, 0 }
}; };
@ -6325,6 +6327,7 @@ init_decl_processing ()
const_ptr_type_node const_ptr_type_node
= build_pointer_type (build_qualified_type (void_type_node, = build_pointer_type (build_qualified_type (void_type_node,
TYPE_QUAL_CONST)); TYPE_QUAL_CONST));
vtt_parm_type = build_pointer_type (const_ptr_type_node);
c_common_nodes_and_builtins (1, flag_no_builtin, flag_no_nonansi_builtin); c_common_nodes_and_builtins (1, flag_no_builtin, flag_no_nonansi_builtin);
lang_type_promotes_to = convert_type_from_ellipsis; lang_type_promotes_to = convert_type_from_ellipsis;
@ -8740,7 +8743,7 @@ grokfndecl (ctype, type, declarator, orig_declarator, virtualp, flags, quals,
quals = NULL_TREE; quals = NULL_TREE;
} }
if (IDENTIFIER_OPNAME_P (DECL_NAME (decl))) if (DECL_OVERLOADED_OPERATOR_P (decl))
grok_op_properties (decl, virtualp, check < 0); grok_op_properties (decl, virtualp, check < 0);
if (ctype && decl_function_context (decl)) if (ctype && decl_function_context (decl))
@ -14744,6 +14747,7 @@ lang_mark_tree (t)
ggc_mark_tree (ld->befriending_classes); ggc_mark_tree (ld->befriending_classes);
ggc_mark_tree (ld->saved_tree); ggc_mark_tree (ld->saved_tree);
ggc_mark_tree (ld->cloned_function); ggc_mark_tree (ld->cloned_function);
ggc_mark_tree (ld->vtt_parm);
if (TREE_CODE (t) == TYPE_DECL) if (TREE_CODE (t) == TYPE_DECL)
ggc_mark_tree (ld->u.sorted_fields); ggc_mark_tree (ld->u.sorted_fields);
else if (TREE_CODE (t) == FUNCTION_DECL else if (TREE_CODE (t) == FUNCTION_DECL

View File

@ -924,6 +924,22 @@ grok_x_components (specs)
break; break;
} }
/* Returns a PARM_DECL for a parameter of the indicated TYPE, with the
indicated NAME. */
tree
build_artificial_parm (name, type)
tree name;
tree type;
{
tree parm;
parm = build_decl (PARM_DECL, name, type);
SET_DECL_ARTIFICIAL (parm);
DECL_ARG_TYPE (parm) = type;
return parm;
}
/* Constructors for types with virtual baseclasses need an "in-charge" flag /* Constructors for types with virtual baseclasses need an "in-charge" flag
saying whether this constructor is responsible for initialization of saying whether this constructor is responsible for initialization of
virtual baseclasses or not. All destructors also need this "in-charge" virtual baseclasses or not. All destructors also need this "in-charge"
@ -956,10 +972,7 @@ maybe_retrofit_in_chrg (fn)
return; return;
/* First add it to DECL_ARGUMENTS... */ /* First add it to DECL_ARGUMENTS... */
parm = build_decl (PARM_DECL, in_charge_identifier, integer_type_node); parm = build_artificial_parm (in_charge_identifier, integer_type_node);
/* Mark the artificial `__in_chrg' parameter as "artificial". */
SET_DECL_ARTIFICIAL (parm);
DECL_ARG_TYPE (parm) = integer_type_node;
TREE_READONLY (parm) = 1; TREE_READONLY (parm) = 1;
parms = DECL_ARGUMENTS (fn); parms = DECL_ARGUMENTS (fn);
TREE_CHAIN (parm) = TREE_CHAIN (parms); TREE_CHAIN (parm) = TREE_CHAIN (parms);
@ -978,6 +991,18 @@ maybe_retrofit_in_chrg (fn)
/* Now we've got the in-charge parameter. */ /* Now we've got the in-charge parameter. */
DECL_HAS_IN_CHARGE_PARM_P (fn) = 1; DECL_HAS_IN_CHARGE_PARM_P (fn) = 1;
/* If this is a subobject constructor or destructor, our caller will
pass us a pointer to our VTT. */
if (flag_new_abi && TYPE_USES_VIRTUAL_BASECLASSES (DECL_CONTEXT (fn)))
{
DECL_VTT_PARM (fn) = build_artificial_parm (vtt_parm_identifier,
vtt_parm_type);
DECL_CONTEXT (DECL_VTT_PARM (fn)) = fn;
DECL_USE_VTT_PARM (fn) = build_artificial_parm (NULL_TREE,
boolean_type_node);
DECL_CONTEXT (DECL_USE_VTT_PARM (fn)) = fn;
}
} }
/* Classes overload their constituent function names automatically. /* Classes overload their constituent function names automatically.
@ -1032,12 +1057,9 @@ grokclassfn (ctype, function, flags, quals)
assigned to. */ assigned to. */
this_quals |= TYPE_QUAL_CONST; this_quals |= TYPE_QUAL_CONST;
qual_type = cp_build_qualified_type (type, this_quals); qual_type = cp_build_qualified_type (type, this_quals);
parm = build_decl (PARM_DECL, this_identifier, qual_type); parm = build_artificial_parm (this_identifier, qual_type);
c_apply_type_quals_to_decl (this_quals, parm); c_apply_type_quals_to_decl (this_quals, parm);
/* Mark the artificial `this' parameter as "artificial". */
SET_DECL_ARTIFICIAL (parm);
DECL_ARG_TYPE (parm) = type;
/* We can make this a register, so long as we don't /* We can make this a register, so long as we don't
accidentally complain if someone tries to take its address. */ accidentally complain if someone tries to take its address. */
DECL_REGISTER (parm) = 1; DECL_REGISTER (parm) = 1;

View File

@ -53,6 +53,7 @@ static tree build_new_1 PARAMS ((tree));
static tree get_cookie_size PARAMS ((tree)); static tree get_cookie_size PARAMS ((tree));
static tree build_dtor_call PARAMS ((tree, special_function_kind, int)); static tree build_dtor_call PARAMS ((tree, special_function_kind, int));
static tree build_field_list PARAMS ((tree, tree, int *)); static tree build_field_list PARAMS ((tree, tree, int *));
static tree build_vtbl_address PARAMS ((tree));
/* Set up local variable for this file. MUST BE CALLED AFTER /* Set up local variable for this file. MUST BE CALLED AFTER
INIT_DECL_PROCESSING. */ INIT_DECL_PROCESSING. */
@ -172,7 +173,14 @@ initialize_vtbl_ptrs (addr)
NULL, dfs_unmarked_real_bases_queue_p, list); NULL, dfs_unmarked_real_bases_queue_p, list);
dfs_walk (TYPE_BINFO (type), dfs_unmark, dfs_walk (TYPE_BINFO (type), dfs_unmark,
dfs_marked_real_bases_queue_p, type); dfs_marked_real_bases_queue_p, type);
expand_indirect_vtbls_init (addr);
/* If we're not using thunks, we may need to adjust the deltas in
the vtable to handle virtual base classes correctly. When we are
using thunks, we either use construction vtables (which are
preloaded with the right answers) or nothing (in which case
vitual function calls sometimes don't work right.) */
if (TYPE_USES_VIRTUAL_BASECLASSES (type) && !flag_vtable_thunks)
fixup_all_virtual_upcast_offsets (addr);
} }
/* Subroutine of emit_base_init. */ /* Subroutine of emit_base_init. */
@ -276,7 +284,7 @@ perform_member_init (member, init, explicit)
expr = build_component_ref (current_class_ref, member, NULL_TREE, expr = build_component_ref (current_class_ref, member, NULL_TREE,
explicit); explicit);
expr = build_delete (type, expr, sfk_base_destructor, expr = build_delete (type, expr, sfk_complete_destructor,
LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0); LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0);
if (expr != error_mark_node) if (expr != error_mark_node)
@ -726,6 +734,32 @@ emit_base_init ()
} }
} }
/* Returns the address of the vtable (i.e., the value that should be
assigned to the vptr) for BINFO. */
static tree
build_vtbl_address (binfo)
tree binfo;
{
tree vtbl;
/* Figure out what vtable BINFO's vtable is based on, and mark it as
used. */
vtbl = get_vtbl_decl_for_binfo (binfo);
assemble_external (vtbl);
TREE_USED (vtbl) = 1;
/* Now compute the address to use when initializing the vptr. */
vtbl = BINFO_VTABLE (binfo);
if (TREE_CODE (vtbl) == VAR_DECL)
{
vtbl = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (vtbl)), vtbl);
TREE_CONSTANT (vtbl) = 1;
}
return vtbl;
}
/* This code sets up the virtual function tables appropriate for /* This code sets up the virtual function tables appropriate for
the pointer DECL. It is a one-ply initialization. the pointer DECL. It is a one-ply initialization.
@ -739,23 +773,40 @@ expand_virtual_init (binfo, decl)
tree type = BINFO_TYPE (binfo); tree type = BINFO_TYPE (binfo);
tree vtbl, vtbl_ptr; tree vtbl, vtbl_ptr;
tree vtype, vtype_binfo; tree vtype, vtype_binfo;
tree b; tree vtt_index;
/* Compute the location of the vtable. */ /* Compute the location of the vtable. */
vtype = DECL_CONTEXT (TYPE_VFIELD (type)); vtype = DECL_CONTEXT (TYPE_VFIELD (type));
vtype_binfo = get_binfo (vtype, TREE_TYPE (TREE_TYPE (decl)), 0); vtype_binfo = get_binfo (vtype, TREE_TYPE (TREE_TYPE (decl)), 0);
b = binfo_value (DECL_FIELD_CONTEXT (TYPE_VFIELD (type)), binfo);
/* Compute the initializer for vptr. */
vtbl = build_vtbl_address (binfo);
/* Figure out what vtable BINFO's vtable is based on, and mark it as /* Under the new ABI, we may get this vptr from a VTT, if this is a
used. */ subobject constructor or subobject destructor. */
vtbl = get_vtbl_decl_for_binfo (b); vtt_index = BINFO_VPTR_INDEX (binfo);
assemble_external (vtbl); if (vtt_index)
TREE_USED (vtbl) = 1; {
tree vtbl2;
tree vtt_parm;
/* Now compute the address to use when initializing the vptr. */ /* Compute the value to use, when there's a VTT. */
vtbl = BINFO_VTABLE (b); vtt_parm = DECL_VTT_PARM (current_function_decl);
if (TREE_CODE (vtbl) == VAR_DECL) vtbl2 = build (PLUS_EXPR,
vtbl = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (vtbl)), vtbl); TREE_TYPE (vtt_parm),
vtt_parm,
vtt_index);
vtbl2 = build1 (INDIRECT_REF, TREE_TYPE (vtbl), vtbl2);
/* The actual initializer is the VTT value only in the subobject
constructor. In maybe_clone_body we'll substitute NULL for
the vtt_parm in the case of the non-subobject constructor. */
vtbl = build (COND_EXPR,
TREE_TYPE (vtbl),
DECL_USE_VTT_PARM (current_function_decl),
vtbl2,
vtbl);
}
/* Compute the location of the vtpr. */ /* Compute the location of the vtpr. */
decl = convert_pointer_to_real (vtype_binfo, decl); decl = convert_pointer_to_real (vtype_binfo, decl);

View File

@ -902,6 +902,10 @@ maybe_clone_body (fn)
DECL_SOURCE_LINE (clone) = DECL_SOURCE_LINE (fn); DECL_SOURCE_LINE (clone) = DECL_SOURCE_LINE (fn);
DECL_INLINE (clone) = DECL_INLINE (fn); DECL_INLINE (clone) = DECL_INLINE (fn);
DECL_THIS_INLINE (clone) = DECL_THIS_INLINE (fn); DECL_THIS_INLINE (clone) = DECL_THIS_INLINE (fn);
DECL_COMDAT (clone) = DECL_COMDAT (fn);
DECL_WEAK (clone) = DECL_WEAK (fn);
DECL_ONE_ONLY (clone) = DECL_ONE_ONLY (fn);
DECL_SECTION_NAME (clone) = DECL_SECTION_NAME (fn);
/* Start processing the function. */ /* Start processing the function. */
push_to_top_level (); push_to_top_level ();
@ -934,7 +938,31 @@ maybe_clone_body (fn)
in_charge = in_charge_arg_for_name (DECL_NAME (clone)); in_charge = in_charge_arg_for_name (DECL_NAME (clone));
splay_tree_insert (id.decl_map, splay_tree_insert (id.decl_map,
(splay_tree_key) parm, (splay_tree_key) parm,
(splay_tree_key) in_charge); (splay_tree_value) in_charge);
/* For a subobject constructor or destructor, the next
argument is the VTT parameter. Remap the VTT_PARM
from the CLONE to this parameter. */
if (DECL_NEEDS_VTT_PARM_P (clone))
{
splay_tree_insert (id.decl_map,
(splay_tree_key) DECL_VTT_PARM (fn),
(splay_tree_value) clone_parm);
splay_tree_insert (id.decl_map,
(splay_tree_key) DECL_USE_VTT_PARM (fn),
(splay_tree_value) boolean_true_node);
clone_parm = TREE_CHAIN (clone_parm);
}
/* Otherwise, map the VTT parameter to `NULL'. */
else if (DECL_VTT_PARM (fn))
{
splay_tree_insert (id.decl_map,
(splay_tree_key) DECL_VTT_PARM (fn),
(splay_tree_value) null_pointer_node);
splay_tree_insert (id.decl_map,
(splay_tree_key) DECL_USE_VTT_PARM (fn),
(splay_tree_value) boolean_false_node);
}
} }
/* Map other parameters to their equivalents in the cloned /* Map other parameters to their equivalents in the cloned
function. */ function. */

View File

@ -144,7 +144,6 @@ static int protected_accessible_p PARAMS ((tree, tree, tree));
static int friend_accessible_p PARAMS ((tree, tree, tree)); static int friend_accessible_p PARAMS ((tree, tree, tree));
static void setup_class_bindings PARAMS ((tree, int)); static void setup_class_bindings PARAMS ((tree, int));
static int template_self_reference_p PARAMS ((tree, tree)); static int template_self_reference_p PARAMS ((tree, tree));
static void fixup_all_virtual_upcast_offsets PARAMS ((tree, tree));
static tree get_shared_vbase_if_not_primary PARAMS ((tree, void *)); static tree get_shared_vbase_if_not_primary PARAMS ((tree, void *));
static tree dfs_find_vbase_instance PARAMS ((tree, void *)); static tree dfs_find_vbase_instance PARAMS ((tree, void *));
static tree dfs_get_pure_virtuals PARAMS ((tree, void *)); static tree dfs_get_pure_virtuals PARAMS ((tree, void *));
@ -2770,14 +2769,14 @@ fixup_virtual_upcast_offsets (real_binfo, binfo, init_self, can_elide, addr, ori
/* Fixup all the virtual upcast offsets for TYPE. DECL_PTR is the /* Fixup all the virtual upcast offsets for TYPE. DECL_PTR is the
address of the sub-object being initialized. */ address of the sub-object being initialized. */
static void void
fixup_all_virtual_upcast_offsets (type, decl_ptr) fixup_all_virtual_upcast_offsets (decl_ptr)
tree type;
tree decl_ptr; tree decl_ptr;
{ {
tree if_stmt; tree if_stmt;
tree in_charge_node; tree in_charge_node;
tree vbases; tree vbases;
tree type;
/* Only tweak the vtables if we're in charge. */ /* Only tweak the vtables if we're in charge. */
in_charge_node = current_in_charge_parm; in_charge_node = current_in_charge_parm;
@ -2791,6 +2790,7 @@ fixup_all_virtual_upcast_offsets (type, decl_ptr)
/* Iterate through the virtual bases, fixing up the upcast offset /* Iterate through the virtual bases, fixing up the upcast offset
for each one. */ for each one. */
type = TREE_TYPE (TREE_TYPE (decl_ptr));
for (vbases = CLASSTYPE_VBASECLASSES (type); for (vbases = CLASSTYPE_VBASECLASSES (type);
vbases; vbases;
vbases = TREE_CHAIN (vbases)) vbases = TREE_CHAIN (vbases))
@ -2820,22 +2820,6 @@ fixup_all_virtual_upcast_offsets (type, decl_ptr)
finish_if_stmt (); finish_if_stmt ();
} }
/* Generate the code needed to initialize all the virtual function
table slots of all the virtual baseclasses. ADDR points to the
address of the complete object we are initializing. */
void
expand_indirect_vtbls_init (addr)
tree addr;
{
tree type;
type = TREE_TYPE (TREE_TYPE (addr));
if (TYPE_USES_VIRTUAL_BASECLASSES (type))
fixup_all_virtual_upcast_offsets (type, addr);
}
/* get virtual base class types. /* get virtual base class types.
This adds type to the vbase_types list in reverse dfs order. This adds type to the vbase_types list in reverse dfs order.
Ordering is very important, so don't change it. */ Ordering is very important, so don't change it. */

View File

@ -1257,15 +1257,15 @@ setup_vtbl_ptr ()
tree compound_stmt; tree compound_stmt;
int saved_cfnd; int saved_cfnd;
/* If the dtor is empty, and we know there is not possible way we /* If the dtor is empty, and we know there is not any possible
could use any vtable entries, before they are possibly set by way we could use any vtable entries, before they are possibly
a base class dtor, we don't have to setup the vtables, as we set by a base class dtor, we don't have to setup the vtables,
know that any base class dtoring will set up any vtables it as we know that any base class dtor will set up any vtables
needs. We avoid MI, because one base class dtor can do a it needs. We avoid MI, because one base class dtor can do a
virtual dispatch to an overridden function that would need to virtual dispatch to an overridden function that would need to
have a non-related vtable set up, we cannot avoid setting up have a non-related vtable set up, we cannot avoid setting up
vtables in that case. We could change this to see if there is vtables in that case. We could change this to see if there
just one vtable. */ is just one vtable. */
if_stmt = begin_if_stmt (); if_stmt = begin_if_stmt ();
/* If it is not safe to avoid setting up the vtables, then /* If it is not safe to avoid setting up the vtables, then

View File

@ -847,7 +847,7 @@ make_binfo (offset, binfo, vtable, virtuals)
tree offset, binfo; tree offset, binfo;
tree vtable, virtuals; tree vtable, virtuals;
{ {
tree new_binfo = make_tree_vec (8); tree new_binfo = make_tree_vec (10);
tree type; tree type;
if (TREE_CODE (binfo) == TREE_VEC) if (TREE_CODE (binfo) == TREE_VEC)

View File

@ -0,0 +1,51 @@
// Origin: Mark Mitchell <mark@codesourcery.com>
// Special g++ Options: -w
int result;
struct A {
A ();
int i;
};
A* ap;
A::A ()
{
ap = this;
}
struct B : virtual public A
{
B ();
~B ();
int j;
};
B::B () {
if ((A*) this != ap)
result = 1;
}
B::~B () {
if ((A*) this != ap)
result = 1;
}
struct C : public B {
};
struct D : public C, public B
{
};
int main ()
{
{
D d;
}
return result;
}

View File

@ -0,0 +1,36 @@
// Origin: Mark Mitchell <mark@codesourcery.com>
int i;
struct A
{
~A ();
};
A::~A () {
i = 1;
}
struct B : virtual public A {
};
struct C {
C ();
B b;
};
C::C () {
throw 3;
}
int main ()
{
try {
C c;
} catch (...) {
}
if (i != 1)
return 1;
}