Commit 31f8e4f3 by Mark Mitchell Committed by Mark Mitchell

cp-tree.h (BV_USE_VCALL_INDEX_P): New macro.

	* cp-tree.h (BV_USE_VCALL_INDEX_P): New macro.
	(BV_GENERATE_THUNK_WITH_VTABLE_P): Likewise.
	(lang_decl_flags): Add generate_with_vtable_p.  Make vcall_offset
	a tree, not an int.
	(THUNK_GENERATE_WITH_VTABLE_P): New macro.
	(make_thunk): Change prototype.
	(emit_thunk): Rename to use_thunk.
	(mangle_thunk): Change prototype.
	* class.c (get_derived_offset): Simplify.
	(copy_virtuals): Clear BV_USE_VCALL_INDEX_P and
	BV_GENERATE_THUNK_WITH_VTABLE_P.
	(build_primary_vtable): Simplify.
	(add_virtual_function): Use BV_FN, rather than TREE_VALUE.
	(dfs_find_base): Remove.
	(update_vtable_entry_for_fn): Correct bug in finding the base
	where a virtual function was first declared.  Figure out whether
	or not to emit a vcall-thunk with the vtables in which it appears.
	Correct logic for deciding whether to use an ordinary thunk, or a
	vcall thunk.
	(finish_struct_1): Remove unnecssary code.
	(build_vtbl_initializer): Use ssize_int for the running counter of
	negative indices.
	(build_vtbl_initializer): Only use vcall thunks where necessary.
	Mark thunks as needing to be emitted with their vtables, or not.
	(build_vbase_offset_vtbl_entries): Adjust for use of ssize_int in
	indices.  Use size_binop.
	(dfs_build_vcall_offset_vtbl_entries): Don't rely on
	BINFO_PRIMARY_MARKED_P here.  Use BV_FN consistently.  Use
	size_binop.
	(build_rtti_vtbl_entries): Adjust call to build_vtable_entry.
	(build_vtable_entry): Mark thunks as needing to be emitted with
	their vtables, or not.
	* decl.c (lang_mark_tree): Mark the vcall_offset in a thunk.
	* decl2.c (mark_vtable_entries): Use use_thunk instead of
	emit_thunk.
	* dump.c (dequeue_and_dump): Remove dead code.  Dump new thunk
	information.
	* error.c (dump_expr): Use BV_FN.
	* mangle.c (mangle_thunk): Adjust now that vcall_offset is a tree,
	not an int.
	* method.c (make_thunk): Likewise.
	(emit_thunk): Rename to use_thunk.  Allow callers to decide
	whether or not to actually emit the thunk.  Adjust for changes in
	representation of vcall offsets.
	* search.c (dfs_get_pure_virtuals): Use BV_FN.
	* semantics.c (emit_associated_thunks): New function.
	(expand_body): Use it.
	* ir.texi: Adjust decriptions of thunks.

From-SVN: r34656
parent 11fc1858
2000-06-22 Mark Mitchell <mark@codesourcery.com>
* cp-tree.h (BV_USE_VCALL_INDEX_P): New macro.
(BV_GENERATE_THUNK_WITH_VTABLE_P): Likewise.
(lang_decl_flags): Add generate_with_vtable_p. Make vcall_offset
a tree, not an int.
(THUNK_GENERATE_WITH_VTABLE_P): New macro.
(make_thunk): Change prototype.
(emit_thunk): Rename to use_thunk.
(mangle_thunk): Change prototype.
* class.c (get_derived_offset): Simplify.
(copy_virtuals): Clear BV_USE_VCALL_INDEX_P and
BV_GENERATE_THUNK_WITH_VTABLE_P.
(build_primary_vtable): Simplify.
(add_virtual_function): Use BV_FN, rather than TREE_VALUE.
(dfs_find_base): Remove.
(update_vtable_entry_for_fn): Correct bug in finding the base
where a virtual function was first declared. Figure out whether
or not to emit a vcall-thunk with the vtables in which it appears.
Correct logic for deciding whether to use an ordinary thunk, or a
vcall thunk.
(finish_struct_1): Remove unnecssary code.
(build_vtbl_initializer): Use ssize_int for the running counter of
negative indices.
(build_vtbl_initializer): Only use vcall thunks where necessary.
Mark thunks as needing to be emitted with their vtables, or not.
(build_vbase_offset_vtbl_entries): Adjust for use of ssize_int in
indices. Use size_binop.
(dfs_build_vcall_offset_vtbl_entries): Don't rely on
BINFO_PRIMARY_MARKED_P here. Use BV_FN consistently. Use
size_binop.
(build_rtti_vtbl_entries): Adjust call to build_vtable_entry.
(build_vtable_entry): Mark thunks as needing to be emitted with
their vtables, or not.
* decl.c (lang_mark_tree): Mark the vcall_offset in a thunk.
* decl2.c (mark_vtable_entries): Use use_thunk instead of
emit_thunk.
* dump.c (dequeue_and_dump): Remove dead code. Dump new thunk
information.
* error.c (dump_expr): Use BV_FN.
* mangle.c (mangle_thunk): Adjust now that vcall_offset is a tree,
not an int.
* method.c (make_thunk): Likewise.
(emit_thunk): Rename to use_thunk. Allow callers to decide
whether or not to actually emit the thunk. Adjust for changes in
representation of vcall offsets.
* search.c (dfs_get_pure_virtuals): Use BV_FN.
* semantics.c (emit_associated_thunks): New function.
(expand_body): Use it.
* ir.texi: Adjust decriptions of thunks.
2000-06-22 Jason Merrill <jason@redhat.com>
* pt.c (tsubst_decl, case FUNCTION_DECL): Clear DECL_SAVED_TREE.
......
......@@ -45,6 +45,7 @@ Boston, MA 02111-1307, USA. */
SCOPE_BEGIN_P (in SCOPE_STMT)
CTOR_BEGIN_P (in CTOR_STMT)
DECL_PRETTY_FUNCTION_P (in VAR_DECL)
BV_USE_VCALL_INDEX_P (in the BINFO_VIRTUALS TREE_LIST)
1: IDENTIFIER_VIRTUAL_P.
TI_PENDING_TEMPLATE_FLAG.
TEMPLATE_PARMS_FOR_INLINE.
......@@ -57,6 +58,7 @@ Boston, MA 02111-1307, USA. */
ICS_ELLIPSIS_FLAG (in _CONV)
STMT_IS_FULL_EXPR_P (in _STMT)
BINFO_ACCESS (in BINFO)
BV_GENERATE_THUNK_WITH_VTABLE_P (in TREE_LIST)
2: IDENTIFIER_OPNAME_P.
TYPE_POLYMORHPIC_P (in _TYPE)
ICS_THIS_FLAG (in _CONV)
......@@ -128,7 +130,9 @@ Boston, MA 02111-1307, USA. */
the this pointer points to an object of the base class.
The BV_VCALL_INDEX of each node, if non-NULL, gives the vtable
index of the vcall offset for this entry.
index of the vcall offset for this entry. If
BV_USE_VCALL_INDEX_P then the corresponding vtable entry should
use a virtual thunk, as opposed to an ordinary thunk.
The BV_FN is the declaration for the virtual function itself.
When CLASSTYPE_COM_INTERFACE_P does not hold, the first entry
......@@ -1841,6 +1845,15 @@ struct lang_type
/* The function to call. */
#define BV_FN(NODE) (TREE_VALUE (NODE))
/* Nonzero if we should use a virtual thunk for this entry. */
#define BV_USE_VCALL_INDEX_P(NODE) \
(TREE_LANG_FLAG_0 (NODE))
/* Nonzero if we should generate this thunk when the vtable that
references it is emitted, rather than with the final overrider. */
#define BV_GENERATE_THUNK_WITH_VTABLE_P(NODE) \
(TREE_LANG_FLAG_1 (NODE))
/* The most derived class. */
......@@ -1901,7 +1914,8 @@ struct lang_decl_flags
unsigned tinfo_fn_p : 1;
unsigned assignment_operator_p : 1;
unsigned anticipated_p : 1;
unsigned dummy : 2;
unsigned generate_with_vtable_p : 1;
unsigned dummy : 1;
tree context;
......@@ -1924,7 +1938,7 @@ struct lang_decl_flags
/* In a FUNCTION_DECL for which DECL_THUNK_P holds, this is
THUNK_VCALL_OFFSET. */
HOST_WIDE_INT vcall_offset;
tree vcall_offset;
} u2;
};
......@@ -3141,6 +3155,10 @@ extern int flag_new_for_scope;
#define THUNK_VCALL_OFFSET(DECL) \
(DECL_LANG_SPECIFIC (DECL)->decl_flags.u2.vcall_offset)
/* Nonzero if this thunk should be generated with the vtable that
references it. */
#define THUNK_GENERATE_WITH_VTABLE_P(DECL) \
(DECL_LANG_SPECIFIC (DECL)->decl_flags.generate_with_vtable_p)
/* These macros provide convenient access to the various _STMT nodes
created when parsing template declarations. */
......@@ -4244,8 +4262,8 @@ extern tree build_overload_with_type PARAMS ((tree, tree));
extern tree build_destructor_name PARAMS ((tree));
extern tree build_opfncall PARAMS ((enum tree_code, int, tree, tree, tree));
extern tree hack_identifier PARAMS ((tree, tree));
extern tree make_thunk PARAMS ((tree, int, int));
extern void emit_thunk PARAMS ((tree));
extern tree make_thunk PARAMS ((tree, tree, tree, int));
extern void use_thunk PARAMS ((tree, int));
extern void synthesize_method PARAMS ((tree));
extern tree get_id_2 PARAMS ((const char *, tree));
extern tree implicitly_declare_fn PARAMS ((special_function_kind, tree, int));
......@@ -4718,7 +4736,7 @@ extern tree mangle_typeinfo_string_for_type PARAMS ((tree));
extern tree mangle_vtbl_for_type PARAMS ((tree));
extern tree mangle_vtt_for_type PARAMS ((tree));
extern tree mangle_ctor_vtbl_for_type PARAMS ((tree, tree));
extern tree mangle_thunk PARAMS ((tree, int, int));
extern tree mangle_thunk PARAMS ((tree, tree, tree));
extern tree mangle_conv_op_name_for_type PARAMS ((tree));
extern tree mangle_guard_variable PARAMS ((tree));
......
......@@ -15063,6 +15063,8 @@ lang_mark_tree (t)
&& !DECL_GLOBAL_DTOR_P (t)
&& !DECL_THUNK_P (t))
ggc_mark_tree (ld->decl_flags.u2.access);
else if (DECL_THUNK_P (t))
ggc_mark_tree (ld->decl_flags.u2.vcall_offset);
ggc_mark_tree (ld->decl_flags.context);
if (TREE_CODE (t) != NAMESPACE_DECL)
ggc_mark_tree (ld->decl_flags.u.template_info);
......
......@@ -2425,11 +2425,12 @@ mark_vtable_entries (decl)
fn = TREE_OPERAND (fnaddr, 0);
TREE_ADDRESSABLE (fn) = 1;
if (DECL_THUNK_P (fn) && DECL_EXTERNAL (fn))
{
DECL_EXTERNAL (fn) = 0;
emit_thunk (fn);
}
/* When we don't have vcall offsets, we output thunks whenever
we output the vtables that contain them. With vcall offsets,
we know all the thunks we'll need when we emit a virtual
function, so we emit the thunks there instead. */
if (DECL_THUNK_P (fn))
use_thunk (fn, THUNK_GENERATE_WITH_VTABLE_P (fn));
mark_used (fn);
}
}
......
......@@ -566,7 +566,7 @@ dequeue_and_dump (di)
dump_string(di, "extern");
else
dump_string (di, "static");
if (TREE_CODE (t) == FUNCTION_DECL)
if (!DECL_THUNK_P (t))
{
if (DECL_FUNCTION_MEMBER_P (t))
dump_string (di, "member");
......@@ -578,13 +578,6 @@ dequeue_and_dump (di)
dump_string (di, "operator");
if (DECL_CONV_FN_P (t))
dump_string (di, "conversion");
if (DECL_THUNK_P (t))
{
dump_string (di, "thunk");
dump_int (di, "dlta", THUNK_DELTA (t));
dump_int (di, "vcll", THUNK_VCALL_OFFSET (t));
dump_child ("fn", DECL_INITIAL (t));
}
if (DECL_GLOBAL_CTOR_P (t) || DECL_GLOBAL_DTOR_P (t))
{
if (DECL_GLOBAL_CTOR_P (t))
......@@ -600,8 +593,10 @@ dequeue_and_dump (di)
}
else
{
dump_string (di, "thunk");
dump_int (di, "dlta", THUNK_DELTA (t));
dump_child ("init", DECL_INITIAL (t));
dump_child ("vcll", THUNK_VCALL_OFFSET (t));
dump_child ("fn", DECL_INITIAL (t));
}
break;
......
......@@ -1867,7 +1867,7 @@ dump_expr (t, flags)
}
if (virtuals)
{
dump_expr (TREE_VALUE (virtuals),
dump_expr (BV_FN (virtuals),
flags | TS_EXPR_PARENS);
break;
}
......
......@@ -1040,8 +1040,8 @@ returning to the thunk. The first parameter to the thunk is always the
value. (The @code{THUNK_DELTA} is an @code{int}, not an
@code{INTEGER_CST}.)
Then, if @code{THUNK_VCALL_OFFSET} (also an @code{int}) is non-zero the
adjusted @code{this} pointer must be adjusted again. The complete
Then, if @code{THUNK_VCALL_OFFSET} (an @code{INTEGER_CST}) is non-zero
the adjusted @code{this} pointer must be adjusted again. The complete
calculation is given by the following pseudo-code:
@example
......
......@@ -2076,7 +2076,7 @@ mangle_ctor_vtbl_for_type (type, binfo)
/* Return an identifier for the mangled name of a thunk to FN_DECL.
OFFSET is the initial adjustment to this used to find the vptr. If
VCALL_OFFSET is non-zero, this is a virtual thunk, and it is the
VCALL_OFFSET is non-NULL, this is a virtual thunk, and it is the
vtbl offset in bytes.
<special-name> ::= Th <offset number> _ <base encoding>
......@@ -2087,8 +2087,8 @@ mangle_ctor_vtbl_for_type (type, binfo)
tree
mangle_thunk (fn_decl, offset, vcall_offset)
tree fn_decl;
int offset;
int vcall_offset;
tree offset;
tree vcall_offset;
{
const char *result;
......@@ -2104,14 +2104,14 @@ mangle_thunk (fn_decl, offset, vcall_offset)
write_char ('h');
/* For either flavor, write the offset to this. */
write_signed_number (offset);
write_integer_cst (offset);
write_char ('_');
/* For a virtual thunk, add the vcall offset. */
if (vcall_offset != 0)
if (vcall_offset)
{
/* Virtual thunk. Write the vcall offset and base type name. */
write_signed_number (vcall_offset);
write_integer_cst (vcall_offset);
write_char ('_');
}
......
......@@ -2063,15 +2063,29 @@ hack_identifier (value, name)
DELTA is the offset to this and VCALL_INDEX is zero. */
tree
make_thunk (function, delta, vcall_index)
make_thunk (function, delta, vcall_index, generate_with_vtable_p)
tree function;
int delta;
int vcall_index;
tree delta;
tree vcall_index;
int generate_with_vtable_p;
{
tree thunk_id;
tree thunk;
tree func_decl;
int vcall_offset = vcall_index * int_size_in_bytes (vtable_entry_type);
tree vcall_offset;
HOST_WIDE_INT d;
/* Scale the VCALL_INDEX to be in terms of bytes. */
if (vcall_index)
vcall_offset
= size_binop (MULT_EXPR,
vcall_index,
convert (ssizetype,
TYPE_SIZE_UNIT (vtable_entry_type)));
else
vcall_offset = NULL_TREE;
d = tree_low_cst (delta, 0);
if (TREE_CODE (function) != ADDR_EXPR)
abort ();
......@@ -2080,22 +2094,23 @@ make_thunk (function, delta, vcall_index)
abort ();
if (flag_new_abi)
thunk_id = mangle_thunk (TREE_OPERAND (function, 0), delta, vcall_offset);
thunk_id = mangle_thunk (TREE_OPERAND (function, 0),
delta, vcall_offset);
else
{
OB_INIT ();
OB_PUTS ("__thunk_");
if (delta > 0)
if (d > 0)
{
OB_PUTC ('n');
icat (delta);
icat (d);
}
else
icat (-delta);
icat (-d);
OB_PUTC ('_');
if (vcall_index)
{
icat (vcall_index);
icat (tree_low_cst (vcall_index, 0));
OB_PUTC ('_');
}
OB_PUTID (DECL_ASSEMBLER_NAME (func_decl));
......@@ -2121,8 +2136,9 @@ make_thunk (function, delta, vcall_index)
comdat_linkage (thunk);
SET_DECL_THUNK_P (thunk);
DECL_INITIAL (thunk) = function;
THUNK_DELTA (thunk) = delta;
THUNK_DELTA (thunk) = d;
THUNK_VCALL_OFFSET (thunk) = vcall_offset;
THUNK_GENERATE_WITH_VTABLE_P (thunk) = generate_with_vtable_p;
/* The thunk itself is not a constructor or destructor, even if
the thing it is thunking to is. */
DECL_INTERFACE_KNOWN (thunk) = 1;
......@@ -2142,6 +2158,8 @@ make_thunk (function, delta, vcall_index)
DECL_DEFERRED_FN (thunk) = 0;
/* So that finish_file can write out any thunks that need to be: */
pushdecl_top_level (thunk);
/* Create RTL for this thunk so that its address can be taken. */
make_function_rtl (thunk);
}
return thunk;
}
......@@ -2149,17 +2167,20 @@ make_thunk (function, delta, vcall_index)
/* Emit the definition of a C++ multiple inheritance vtable thunk. */
void
emit_thunk (thunk_fndecl)
use_thunk (thunk_fndecl, emit_p)
tree thunk_fndecl;
int emit_p;
{
tree fnaddr;
tree function;
int delta;
int vcall_offset;
tree vcall_offset;
HOST_WIDE_INT delta;
if (TREE_ASM_WRITTEN (thunk_fndecl))
return;
fnaddr = DECL_INITIAL (thunk_fndecl);
if (TREE_CODE (DECL_INITIAL (thunk_fndecl)) != ADDR_EXPR)
/* We already turned this thunk into an ordinary function.
There's no need to process this thunk again. (We can't just
......@@ -2167,16 +2188,25 @@ emit_thunk (thunk_fndecl)
FNADDR_FROM_VTABLE_ENTRY and friends.) */
return;
fnaddr = DECL_INITIAL (thunk_fndecl);
function = TREE_OPERAND (fnaddr, 0);
delta = THUNK_DELTA (thunk_fndecl);
vcall_offset = THUNK_VCALL_OFFSET (thunk_fndecl);
/* Thunks are always addressable; they only appear in vtables. */
TREE_ADDRESSABLE (thunk_fndecl) = 1;
/* Figure out what function is being thunked to. It's referenced in
this translation unit. */
function = TREE_OPERAND (fnaddr, 0);
TREE_ADDRESSABLE (function) = 1;
mark_used (function);
TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (function)) = 1;
if (!emit_p)
return;
if (current_function_decl)
abort ();
delta = THUNK_DELTA (thunk_fndecl);
vcall_offset = THUNK_VCALL_OFFSET (thunk_fndecl);
/* And, if we need to emit the thunk, it's used. */
mark_used (thunk_fndecl);
/* This thunk is actually defined. */
DECL_EXTERNAL (thunk_fndecl) = 0;
if (flag_syntax_only)
{
......@@ -2184,14 +2214,13 @@ emit_thunk (thunk_fndecl)
return;
}
push_to_top_level ();
#ifdef ASM_OUTPUT_MI_THUNK
if (vcall_offset == 0)
if (!vcall_offset)
{
const char *fnname;
current_function_decl = thunk_fndecl;
/* Make sure we build up its RTL before we go onto the
temporary obstack. */
make_function_rtl (thunk_fndecl);
DECL_RESULT (thunk_fndecl)
= build_decl (RESULT_DECL, 0, integer_type_node);
fnname = XSTR (XEXP (DECL_RTL (thunk_fndecl), 0), 0);
......@@ -2230,17 +2259,15 @@ emit_thunk (thunk_fndecl)
DECL_ARGUMENTS (thunk_fndecl) = a;
DECL_RESULT (thunk_fndecl) = NULL_TREE;
push_to_top_level ();
start_function (NULL_TREE, thunk_fndecl, NULL_TREE, SF_PRE_PARSED);
store_parm_decls ();
/* Adjust the this pointer by the constant. */
t = ssize_int (delta);
TREE_TYPE (t) = signed_type (sizetype);
t = fold (build (PLUS_EXPR, TREE_TYPE (a), a, t));
/* If there's a vcall offset, look up that value in the vtable and
adjust the `this' pointer again. */
if (vcall_offset != 0)
if (!integer_zerop (vcall_offset))
{
tree orig_this;
......@@ -2254,7 +2281,7 @@ emit_thunk (thunk_fndecl)
/* Form the vtable address. */
t = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (t)), t);
/* Find the entry with the vcall offset. */
t = build (PLUS_EXPR, TREE_TYPE (t), t, ssize_int (vcall_offset));
t = build (PLUS_EXPR, TREE_TYPE (t), t, vcall_offset);
/* Calculate the offset itself. */
t = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (t)), t);
/* Adjust the `this' pointer. */
......@@ -2281,8 +2308,9 @@ emit_thunk (thunk_fndecl)
BLOCK_VARS (DECL_INITIAL (thunk_fndecl))
= DECL_ARGUMENTS (thunk_fndecl);
expand_body (finish_function (0));
pop_from_top_level ();
}
pop_from_top_level ();
}
/* Code for synthesizing methods which have default semantics defined. */
......
......@@ -2295,9 +2295,9 @@ dfs_get_pure_virtuals (binfo, data)
for (virtuals = BINFO_VIRTUALS (binfo);
virtuals;
virtuals = TREE_CHAIN (virtuals))
if (DECL_PURE_VIRTUAL_P (TREE_VALUE (virtuals)))
if (DECL_PURE_VIRTUAL_P (BV_FN (virtuals)))
CLASSTYPE_PURE_VIRTUALS (type)
= tree_cons (NULL_TREE, TREE_VALUE (virtuals),
= tree_cons (NULL_TREE, BV_FN (virtuals),
CLASSTYPE_PURE_VIRTUALS (type));
}
......@@ -2341,7 +2341,7 @@ get_pure_virtuals (type)
virtuals;
virtuals = TREE_CHAIN (virtuals))
{
tree base_fndecl = TREE_VALUE (virtuals);
tree base_fndecl = BV_FN (virtuals);
if (DECL_NEEDS_FINAL_OVERRIDER_P (base_fndecl))
cp_error ("`%#D' needs a final overrider", base_fndecl);
}
......
......@@ -50,6 +50,7 @@ static tree expand_cond PARAMS ((tree));
static tree maybe_convert_cond PARAMS ((tree));
static tree simplify_aggr_init_exprs_r PARAMS ((tree *, int *, void *));
static void deferred_type_access_control PARAMS ((void));
static void emit_associated_thunks PARAMS ((tree));
/* Record the fact that STMT was the last statement added to the
statement tree. */
......@@ -2962,6 +2963,53 @@ simplify_aggr_init_exprs_r (tp, walk_subtrees, data)
return NULL_TREE;
}
/* Emit all thunks to FN that should be emitted when FN is emitted. */
static void
emit_associated_thunks (fn)
tree fn;
{
/* When we use vcall offsets, we emit thunks with the virtual
functions to which they thunk. The whole point of vcall offsets
is so that you can know statically the entire set of thunks that
will ever be needed for a given virtual function, thereby
enabling you to output all the thunks with the function itself. */
if (vcall_offsets_in_vtable_p () && DECL_VIRTUAL_P (fn))
{
tree binfo;
tree v;
for (binfo = TYPE_BINFO (DECL_CONTEXT (fn));
binfo;
binfo = TREE_CHAIN (binfo))
for (v = BINFO_VIRTUALS (binfo); v; v = TREE_CHAIN (v))
if (BV_FN (v) == fn
&& (!integer_zerop (BV_DELTA (v))
|| BV_VCALL_INDEX (v)))
{
tree thunk;
tree vcall_index;
if (BV_USE_VCALL_INDEX_P (v))
{
vcall_index = BV_VCALL_INDEX (v);
my_friendly_assert (vcall_index != NULL_TREE, 20000621);
}
else
vcall_index = NULL_TREE;
thunk = make_thunk (build1 (ADDR_EXPR,
vfunc_ptr_type_node,
fn),
BV_DELTA (v),
vcall_index,
/*generate_with_vtable_p=*/0);
use_thunk (thunk, /*emit_p=*/1);
}
}
}
/* Generate RTL for FN. */
void
......@@ -3037,6 +3085,9 @@ expand_body (fn)
return;
}
/* Emit any thunks that should be emitted at the same time as FN. */
emit_associated_thunks (fn);
timevar_push (TV_INTEGRATION);
/* Optimize the body of the function before expanding it. */
......
extern "C" void printf (const char*, ...);
struct A
{
virtual void f () {
printf ("%x\n", this);
}
};
struct B : public A
{
};
struct C : public A
{
};
struct D : virtual public B, public C
{
};
int main ()
{
D d;
A* a1 = (A*) (B*) &d;
A* a2 = (A*) (C*) &d;
a1->f ();
a2->f ();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment