Compiler side new abi rtti (not enabled).
* cp-tree.h (new_abi_rtti_p): New macro. (emit_support_tinfos): Prototype new function. (tinfo_decl_p): Likewise. (emit_tinfo_decl): Likwise. * rtti.c (TINFO_PSEUDO_TYPE, TINFO_VTABLE_DECL): New accessor macros. (doing_runtime): New local static. (init_rtti_processing): Add new-abi initializer. (get_tinfo_decl): Add new-abi logic. (tinfo_from_decl): Likewise. (build_dynamic_cast_1): Likewise. (qualifier_flags): New static function. (tinfo_base_init): Likewise. (generic_initializer): Likewise. (ptr_ref_initializer): Likewise. (ptmd_initializer): Likewise. (class_hint_flags): Likewise. (class_initializer): Likewise. (synthesize_tinfo_var): Likewise. (create_real_tinfo_var): Likewise. (create_pseudo_type_info): Likewise. (get_vmi_pseudo_type_info): Likewise. (create_tinfo_types): Likewise. (emit_support_tinfos): New global function. (tinfo_decl_p): New global predicate. (emit_tinfo_decl): New global function. * class.c (set_rtti_entry): Generalize for old and new rtti. (build_vtbl_initializer): Likewise. * decl2.c (finish_file): Likewise. From-SVN: r31668
This commit is contained in:
parent
73565a7129
commit
7267d6924e
@ -1,3 +1,36 @@
|
||||
2000-01-28 Nathan Sidwell <sidwell@codesourcery.com>
|
||||
|
||||
Compiler side new abi rtti (not enabled).
|
||||
* cp-tree.h (new_abi_rtti_p): New macro.
|
||||
(emit_support_tinfos): Prototype new function.
|
||||
(tinfo_decl_p): Likewise.
|
||||
(emit_tinfo_decl): Likwise.
|
||||
* rtti.c (TINFO_PSEUDO_TYPE, TINFO_VTABLE_DECL): New accessor
|
||||
macros.
|
||||
(doing_runtime): New local static.
|
||||
(init_rtti_processing): Add new-abi initializer.
|
||||
(get_tinfo_decl): Add new-abi logic.
|
||||
(tinfo_from_decl): Likewise.
|
||||
(build_dynamic_cast_1): Likewise.
|
||||
(qualifier_flags): New static function.
|
||||
(tinfo_base_init): Likewise.
|
||||
(generic_initializer): Likewise.
|
||||
(ptr_ref_initializer): Likewise.
|
||||
(ptmd_initializer): Likewise.
|
||||
(class_hint_flags): Likewise.
|
||||
(class_initializer): Likewise.
|
||||
(synthesize_tinfo_var): Likewise.
|
||||
(create_real_tinfo_var): Likewise.
|
||||
(create_pseudo_type_info): Likewise.
|
||||
(get_vmi_pseudo_type_info): Likewise.
|
||||
(create_tinfo_types): Likewise.
|
||||
(emit_support_tinfos): New global function.
|
||||
(tinfo_decl_p): New global predicate.
|
||||
(emit_tinfo_decl): New global function.
|
||||
* class.c (set_rtti_entry): Generalize for old and new rtti.
|
||||
(build_vtbl_initializer): Likewise.
|
||||
* decl2.c (finish_file): Likewise.
|
||||
|
||||
Thu Jan 27 20:53:36 2000 Jim Wilson <wilson@cygnus.com>
|
||||
|
||||
* cp/optimize.c (remap_decl): Add walk_tree calls for DECL_SIZE (t)
|
||||
|
@ -963,34 +963,37 @@ static void
|
||||
set_rtti_entry (virtuals, offset, type)
|
||||
tree virtuals, offset, type;
|
||||
{
|
||||
tree fn;
|
||||
tree decl;
|
||||
|
||||
if (CLASSTYPE_COM_INTERFACE (type))
|
||||
return;
|
||||
|
||||
if (flag_rtti)
|
||||
fn = get_tinfo_decl (type);
|
||||
else
|
||||
decl = get_tinfo_decl (type);
|
||||
else if (!new_abi_rtti_p ())
|
||||
/* If someone tries to get RTTI information for a type compiled
|
||||
without RTTI, they're out of luck. By calling __pure_virtual
|
||||
in this case, we give a small clue as to what went wrong. We
|
||||
could consider having a __no_typeinfo function as well, for a
|
||||
more specific hint. */
|
||||
fn = abort_fndecl;
|
||||
decl = abort_fndecl;
|
||||
else
|
||||
/* For the new-abi, we just point to the type_info object. */
|
||||
decl = NULL_TREE;
|
||||
|
||||
if (flag_vtable_thunks)
|
||||
{
|
||||
/* The first slot holds the offset. */
|
||||
TREE_PURPOSE (virtuals) = offset;
|
||||
|
||||
/* The next node holds the function. */
|
||||
/* The next node holds the decl. */
|
||||
virtuals = TREE_CHAIN (virtuals);
|
||||
offset = integer_zero_node;
|
||||
}
|
||||
|
||||
/* This slot holds the function to call. */
|
||||
/* This slot holds the decl. */
|
||||
TREE_PURPOSE (virtuals) = offset;
|
||||
TREE_VALUE (virtuals) = fn;
|
||||
TREE_VALUE (virtuals) = decl;
|
||||
}
|
||||
|
||||
/* Get the VAR_DECL of the vtable for TYPE. TYPE need not be polymorphic,
|
||||
@ -2615,9 +2618,26 @@ build_vtbl_initializer (binfo, t)
|
||||
init = build_vtable_entry (integer_zero_node, init);
|
||||
inits = tree_cons (NULL_TREE, init, inits);
|
||||
|
||||
/* Even in this case, the second entry (the tdesc pointer) is
|
||||
just an ordinary function. */
|
||||
v = TREE_CHAIN (v);
|
||||
|
||||
if (new_abi_rtti_p ())
|
||||
{
|
||||
tree decl = TREE_VALUE (v);
|
||||
|
||||
if (decl)
|
||||
decl = build_unary_op (ADDR_EXPR, decl, 0);
|
||||
else
|
||||
decl = integer_zero_node;
|
||||
decl = build1 (NOP_EXPR, vfunc_ptr_type_node, decl);
|
||||
TREE_CONSTANT (decl) = 1;
|
||||
decl = build_vtable_entry (integer_zero_node, decl);
|
||||
inits = tree_cons (NULL_TREE, decl, inits);
|
||||
|
||||
v = TREE_CHAIN (v);
|
||||
}
|
||||
/* In the old abi the second entry (the tdesc pointer) is
|
||||
just an ordinary function, so it can be dealt with like the
|
||||
virtual functions. */
|
||||
}
|
||||
|
||||
/* Go through all the ordinary virtual functions, building up
|
||||
|
@ -238,6 +238,11 @@ extern int flag_rtti;
|
||||
class). */
|
||||
#define all_overridden_vfuns_in_vtables_p() (flag_new_abi)
|
||||
|
||||
/* Nonzero if we use access type_info objects directly, and use the
|
||||
cross-vendor layout for them. Zero if we use an accessor function
|
||||
to get the type_info object address. */
|
||||
#define new_abi_rtti_p() (0)
|
||||
|
||||
|
||||
/* Language-dependent contents of an identifier. */
|
||||
|
||||
@ -3988,13 +3993,16 @@ extern void init_repo PARAMS ((const char *));
|
||||
extern void finish_repo PARAMS ((void));
|
||||
|
||||
/* in rtti.c */
|
||||
extern void init_rtti_processing PARAMS ((void));
|
||||
extern tree build_typeid PARAMS ((tree));
|
||||
extern tree get_tinfo_decl PARAMS ((tree));
|
||||
extern tree get_typeid PARAMS ((tree));
|
||||
extern tree get_typeid_1 PARAMS ((tree));
|
||||
extern tree build_dynamic_cast PARAMS ((tree, tree));
|
||||
extern void synthesize_tinfo_fn PARAMS ((tree));
|
||||
extern void init_rtti_processing PARAMS((void));
|
||||
extern tree build_typeid PARAMS((tree));
|
||||
extern tree get_tinfo_decl PARAMS((tree));
|
||||
extern tree get_typeid PARAMS((tree));
|
||||
extern tree get_typeid_1 PARAMS((tree));
|
||||
extern tree build_dynamic_cast PARAMS((tree, tree));
|
||||
extern void synthesize_tinfo_fn PARAMS((tree));
|
||||
extern void emit_support_tinfos PARAMS((void));
|
||||
extern int tinfo_decl_p PARAMS((tree, void *));
|
||||
extern int emit_tinfo_decl PARAMS((tree *, void *));
|
||||
|
||||
/* in search.c */
|
||||
extern int types_overlap_p PARAMS ((tree, tree));
|
||||
|
@ -3434,6 +3434,9 @@ finish_file ()
|
||||
varconst_time += this_time - start_time;
|
||||
start_time = get_run_time ();
|
||||
|
||||
if (new_abi_rtti_p ())
|
||||
emit_support_tinfos ();
|
||||
|
||||
do
|
||||
{
|
||||
reconsider = 0;
|
||||
@ -3450,6 +3453,12 @@ finish_file ()
|
||||
/*data=*/0))
|
||||
reconsider = 1;
|
||||
|
||||
/* Write out needed type info variables. Writing out one variable
|
||||
might cause others to be needed. */
|
||||
if (new_abi_rtti_p ()
|
||||
&& walk_globals (tinfo_decl_p, emit_tinfo_decl, /*data=*/0))
|
||||
reconsider = 1;
|
||||
|
||||
/* The list of objects with static storage duration is built up
|
||||
in reverse order. We clear STATIC_AGGREGATES so that any new
|
||||
aggregates added during the initialization of these will be
|
||||
|
871
gcc/cp/rtti.c
871
gcc/cp/rtti.c
@ -33,25 +33,48 @@ Boston, MA 02111-1307, USA. */
|
||||
#define INT_TYPE_SIZE BITS_PER_WORD
|
||||
#endif
|
||||
|
||||
/* Accessors for the type_info objects. We need to remember several things
|
||||
about each of the type_info types. The global tree nodes such as
|
||||
bltn_desc_type_node are TREE_LISTs, and these macros are used to access
|
||||
the required information. */
|
||||
/* The RECORD_TYPE of a type_info derived class. */
|
||||
#define TINFO_PSEUDO_TYPE(NODE) TREE_TYPE (NODE)
|
||||
/* The VAR_DECL of the vtable for the type_info derived class. */
|
||||
#define TINFO_VTABLE_DECL(NODE) TREE_VALUE (NODE)
|
||||
|
||||
extern struct obstack permanent_obstack;
|
||||
|
||||
static tree build_runtime_decl PARAMS ((const char *, tree));
|
||||
static tree build_headof_sub PARAMS ((tree));
|
||||
static tree build_headof PARAMS ((tree));
|
||||
static tree get_tinfo_var PARAMS ((tree));
|
||||
static tree ifnonnull PARAMS ((tree, tree));
|
||||
static tree tinfo_name PARAMS ((tree));
|
||||
static tree get_base_offset PARAMS ((tree, tree));
|
||||
static tree build_dynamic_cast_1 PARAMS ((tree, tree));
|
||||
static void expand_si_desc PARAMS ((tree, tree));
|
||||
static void expand_class_desc PARAMS ((tree, tree));
|
||||
static void expand_attr_desc PARAMS ((tree, tree));
|
||||
static void expand_ptr_desc PARAMS ((tree, tree));
|
||||
static void expand_generic_desc PARAMS ((tree, tree, const char *));
|
||||
static tree throw_bad_cast PARAMS ((void));
|
||||
static tree throw_bad_typeid PARAMS ((void));
|
||||
static tree get_tinfo_decl_dynamic PARAMS ((tree));
|
||||
static tree tinfo_from_decl PARAMS ((tree));
|
||||
static tree build_runtime_decl PARAMS((const char *, tree));
|
||||
static tree build_headof_sub PARAMS((tree));
|
||||
static tree build_headof PARAMS((tree));
|
||||
static tree get_tinfo_var PARAMS((tree));
|
||||
static tree ifnonnull PARAMS((tree, tree));
|
||||
static tree tinfo_name PARAMS((tree));
|
||||
static tree get_base_offset PARAMS((tree, tree));
|
||||
static tree build_dynamic_cast_1 PARAMS((tree, tree));
|
||||
static void expand_si_desc PARAMS((tree, tree));
|
||||
static void expand_class_desc PARAMS((tree, tree));
|
||||
static void expand_attr_desc PARAMS((tree, tree));
|
||||
static void expand_ptr_desc PARAMS((tree, tree));
|
||||
static void expand_generic_desc PARAMS((tree, tree, const char *));
|
||||
static tree throw_bad_cast PARAMS((void));
|
||||
static tree throw_bad_typeid PARAMS((void));
|
||||
static tree get_tinfo_decl_dynamic PARAMS((tree));
|
||||
static tree tinfo_from_decl PARAMS((tree));
|
||||
static int qualifier_flags PARAMS((tree));
|
||||
static tree tinfo_base_init PARAMS((tree, tree));
|
||||
static tree generic_initializer PARAMS((tree, tree));
|
||||
static tree ptr_ref_initializer PARAMS((tree, tree));
|
||||
static tree ptmd_initializer PARAMS((tree, tree));
|
||||
static int class_hint_flags PARAMS((tree));
|
||||
static tree class_initializer PARAMS((tree, tree, tree));
|
||||
static tree synthesize_tinfo_var PARAMS((tree, tree));
|
||||
static tree create_real_tinfo_var PARAMS((tree, tree, tree));
|
||||
static tree create_pseudo_type_info PARAMS((const char *, int, ...));
|
||||
static tree get_vmi_pseudo_type_info PARAMS((int));
|
||||
static void create_tinfo_types PARAMS((void));
|
||||
|
||||
static int doing_runtime = 0;
|
||||
|
||||
void
|
||||
init_rtti_processing ()
|
||||
@ -62,13 +85,21 @@ init_rtti_processing ()
|
||||
(class_type_node, get_identifier ("type_info"), 1);
|
||||
if (flag_honor_std)
|
||||
pop_namespace ();
|
||||
|
||||
if (!new_abi_rtti_p ())
|
||||
{
|
||||
tinfo_decl_id = get_identifier ("__tf");
|
||||
tinfo_decl_type = build_function_type
|
||||
(build_reference_type
|
||||
(build_qualified_type
|
||||
(type_info_type_node, TYPE_QUAL_CONST)),
|
||||
void_list_node);
|
||||
}
|
||||
else
|
||||
{
|
||||
tinfo_decl_id = get_identifier ("__ti");
|
||||
tinfo_decl_type = build_qualified_type
|
||||
(type_info_type_node, TYPE_QUAL_CONST);
|
||||
}
|
||||
tinfo_var_id = get_identifier ("__ti");
|
||||
}
|
||||
|
||||
@ -312,6 +343,7 @@ get_tinfo_var (type)
|
||||
tree arrtype;
|
||||
int size;
|
||||
|
||||
my_friendly_assert (!new_abi_rtti_p (), 20000118);
|
||||
if (IDENTIFIER_GLOBAL_VALUE (tname))
|
||||
return IDENTIFIER_GLOBAL_VALUE (tname);
|
||||
|
||||
@ -357,8 +389,8 @@ tinfo_name (type)
|
||||
}
|
||||
|
||||
/* Returns a decl for a function or variable which can be used to obtain a
|
||||
type_info object for TYPE. The old-abi uses functions, the new-abi will
|
||||
use the type_info object directly. You can take the address of the
|
||||
type_info object for TYPE. The old-abi uses functions, the new-abi
|
||||
uses the type_info object directly. You can take the address of the
|
||||
returned decl, to save the decl. To use the decl call
|
||||
tinfo_from_decl. You must arrange that the decl is mark_used, if
|
||||
actually use it --- decls in vtables are only used if the vtable is
|
||||
@ -379,9 +411,13 @@ get_tinfo_decl (type)
|
||||
|
||||
name = build_overload_with_type (tinfo_decl_id, type);
|
||||
|
||||
if (IDENTIFIER_GLOBAL_VALUE (name))
|
||||
return IDENTIFIER_GLOBAL_VALUE (name);
|
||||
|
||||
d = IDENTIFIER_GLOBAL_VALUE (name);
|
||||
if (d)
|
||||
/* OK */;
|
||||
else if (!new_abi_rtti_p ())
|
||||
{
|
||||
/* The tinfo decl is a function returning a reference to the type_info
|
||||
object. */
|
||||
d = build_lang_decl (FUNCTION_DECL, name, tinfo_decl_type);
|
||||
DECL_EXTERNAL (d) = 1;
|
||||
TREE_PUBLIC (d) = 1;
|
||||
@ -393,7 +429,29 @@ get_tinfo_decl (type)
|
||||
pushdecl_top_level (d);
|
||||
make_function_rtl (d);
|
||||
mark_inline_for_output (d);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The tinfo decl is the type_info object itself. We make all
|
||||
tinfo objects look as type_info, even though they will end up
|
||||
being a subclass of that when emitted. This means the we'll
|
||||
erroneously think we know the dynamic type -- be careful in the
|
||||
runtime. */
|
||||
d = build_lang_decl (VAR_DECL, name, tinfo_decl_type);
|
||||
|
||||
DECL_ARTIFICIAL (d) = 1;
|
||||
DECL_ALIGN (d) = TYPE_ALIGN (ptr_type_node);
|
||||
TREE_READONLY (d) = 1;
|
||||
TREE_STATIC (d) = 1;
|
||||
DECL_EXTERNAL (d) = 1;
|
||||
TREE_PUBLIC (d) = 1;
|
||||
DECL_ASSEMBLER_NAME (d) = DECL_NAME (d);
|
||||
cp_finish_decl (d, NULL_TREE, NULL_TREE, 0);
|
||||
|
||||
pushdecl_top_level (d);
|
||||
/* Remember the type it is for. */
|
||||
TREE_TYPE (name) = type;
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
@ -404,7 +462,14 @@ static tree
|
||||
tinfo_from_decl (expr)
|
||||
tree expr;
|
||||
{
|
||||
tree t = build_call (expr, TREE_TYPE (tinfo_decl_type), NULL_TREE);
|
||||
tree t;
|
||||
|
||||
if (!new_abi_rtti_p ())
|
||||
t = build_call (expr, TREE_TYPE (tinfo_decl_type), NULL_TREE);
|
||||
else if (TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE)
|
||||
t = build_indirect_ref (expr, NULL);
|
||||
else
|
||||
t = expr;
|
||||
|
||||
return t;
|
||||
}
|
||||
@ -631,7 +696,7 @@ build_dynamic_cast_1 (type, expr)
|
||||
else
|
||||
{
|
||||
tree retval;
|
||||
tree result, td1, td2, td3, elems, expr2;
|
||||
tree result, td2, td3, elems;
|
||||
tree static_type, target_type, boff;
|
||||
|
||||
/* If we got here, we can't convert statically. Therefore,
|
||||
@ -664,21 +729,6 @@ build_dynamic_cast_1 (type, expr)
|
||||
}
|
||||
}
|
||||
|
||||
/* Since expr is used twice below, save it. */
|
||||
expr = save_expr (expr);
|
||||
|
||||
expr1 = expr;
|
||||
if (tc == REFERENCE_TYPE)
|
||||
expr1 = build_unary_op (ADDR_EXPR, expr1, 0);
|
||||
|
||||
/* Build run-time conversion. */
|
||||
expr2 = build_headof (expr1);
|
||||
|
||||
if (ec == POINTER_TYPE)
|
||||
td1 = get_tinfo_decl_dynamic (build_indirect_ref (expr, NULL_PTR));
|
||||
else
|
||||
td1 = get_tinfo_decl_dynamic (expr);
|
||||
|
||||
target_type = TYPE_MAIN_VARIANT (TREE_TYPE (type));
|
||||
static_type = TYPE_MAIN_VARIANT (TREE_TYPE (exprtype));
|
||||
td2 = build_unary_op (ADDR_EXPR, get_tinfo_decl (target_type), 0);
|
||||
@ -687,6 +737,22 @@ build_dynamic_cast_1 (type, expr)
|
||||
/* Determine how T and V are related. */
|
||||
boff = get_dynamic_cast_base_type (static_type, target_type);
|
||||
|
||||
/* Since expr is used twice below, save it. */
|
||||
expr = save_expr (expr);
|
||||
|
||||
expr1 = expr;
|
||||
if (tc == REFERENCE_TYPE)
|
||||
expr1 = build_unary_op (ADDR_EXPR, expr1, 0);
|
||||
|
||||
if (!new_abi_rtti_p ())
|
||||
{
|
||||
tree expr2 = build_headof (expr1);
|
||||
tree td1 = expr;
|
||||
|
||||
if (ec == POINTER_TYPE)
|
||||
td1 = build_indirect_ref (td1, NULL_PTR);
|
||||
td1 = get_tinfo_decl_dynamic (td1);
|
||||
|
||||
elems = tree_cons
|
||||
(NULL_TREE, td1, tree_cons
|
||||
(NULL_TREE, td2, tree_cons
|
||||
@ -694,13 +760,27 @@ build_dynamic_cast_1 (type, expr)
|
||||
(NULL_TREE, expr2, tree_cons
|
||||
(NULL_TREE, td3, tree_cons
|
||||
(NULL_TREE, expr1, NULL_TREE))))));
|
||||
}
|
||||
else
|
||||
elems = tree_cons
|
||||
(NULL_TREE, expr1, tree_cons
|
||||
(NULL_TREE, td3, tree_cons
|
||||
(NULL_TREE, td2, tree_cons
|
||||
(NULL_TREE, boff, NULL_TREE))));
|
||||
|
||||
dcast_fn = dynamic_cast_node;
|
||||
if (!dcast_fn)
|
||||
{
|
||||
tree tmp;
|
||||
tree tinfo_ptr = build_pointer_type (tinfo_decl_type);
|
||||
tree tinfo_ptr;
|
||||
tree ns = global_namespace;
|
||||
const char *name;
|
||||
|
||||
push_nested_namespace (ns);
|
||||
if (!new_abi_rtti_p ())
|
||||
{
|
||||
tinfo_ptr = build_pointer_type (tinfo_decl_type);
|
||||
name = "__dynamic_cast_2";
|
||||
tmp = tree_cons
|
||||
(NULL_TREE, tinfo_ptr, tree_cons
|
||||
(NULL_TREE, tinfo_ptr, tree_cons
|
||||
@ -708,17 +788,41 @@ build_dynamic_cast_1 (type, expr)
|
||||
(NULL_TREE, ptr_type_node, tree_cons
|
||||
(NULL_TREE, tinfo_ptr, tree_cons
|
||||
(NULL_TREE, ptr_type_node, void_list_node))))));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (flag_honor_std)
|
||||
{
|
||||
push_namespace (get_identifier ("std"));
|
||||
ns = current_namespace;
|
||||
}
|
||||
tinfo_ptr = xref_tag (class_type_node,
|
||||
get_identifier ("__class_type_info"),
|
||||
1);
|
||||
|
||||
tinfo_ptr = build_pointer_type
|
||||
(build_qualified_type
|
||||
(tinfo_ptr, TYPE_QUAL_CONST));
|
||||
name = "__dynamic_cast";
|
||||
tmp = tree_cons
|
||||
(NULL_TREE, const_ptr_type_node, tree_cons
|
||||
(NULL_TREE, tinfo_ptr, tree_cons
|
||||
(NULL_TREE, tinfo_ptr, tree_cons
|
||||
(NULL_TREE, ptrdiff_type_node, void_list_node))));
|
||||
}
|
||||
tmp = build_function_type (ptr_type_node, tmp);
|
||||
dcast_fn = build_lang_decl (FUNCTION_DECL,
|
||||
get_identifier ("__dynamic_cast_2"),
|
||||
get_identifier (name),
|
||||
tmp);
|
||||
DECL_EXTERNAL (dcast_fn) = 1;
|
||||
TREE_PUBLIC (dcast_fn) = 1;
|
||||
DECL_ARTIFICIAL (dcast_fn) = 1;
|
||||
pushdecl_top_level (dcast_fn);
|
||||
pushdecl (dcast_fn);
|
||||
if (new_abi_rtti_p ())
|
||||
/* We want it's name mangling. */
|
||||
set_mangled_name_for_decl (dcast_fn);
|
||||
make_function_rtl (dcast_fn);
|
||||
|
||||
pop_nested_namespace (ns);
|
||||
dynamic_cast_node = dcast_fn;
|
||||
}
|
||||
mark_used (dcast_fn);
|
||||
@ -727,9 +831,10 @@ build_dynamic_cast_1 (type, expr)
|
||||
|
||||
if (tc == REFERENCE_TYPE)
|
||||
{
|
||||
expr1 = throw_bad_cast ();
|
||||
tree bad = throw_bad_cast ();
|
||||
|
||||
result = save_expr (result);
|
||||
return build (COND_EXPR, type, result, result, expr1);
|
||||
return build (COND_EXPR, type, result, result, bad);
|
||||
}
|
||||
|
||||
/* Now back to the type we want from a void*. */
|
||||
@ -1128,6 +1233,7 @@ synthesize_tinfo_fn (fndecl)
|
||||
tree if_stmt;
|
||||
tree then_clause;
|
||||
|
||||
my_friendly_assert (!new_abi_rtti_p (), 20000118);
|
||||
if (at_eof)
|
||||
{
|
||||
import_export_decl (fndecl);
|
||||
@ -1212,3 +1318,676 @@ synthesize_tinfo_fn (fndecl)
|
||||
finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
|
||||
expand_body (finish_function (lineno, 0));
|
||||
}
|
||||
|
||||
/* Return the runtime bit mask encoding the qualifiers of TYPE. */
|
||||
|
||||
static int
|
||||
qualifier_flags (type)
|
||||
tree type;
|
||||
{
|
||||
int flags = 0;
|
||||
/* we want the qualifiers on this type, not any array core, it might have */
|
||||
int quals = TYPE_QUALS (type);
|
||||
|
||||
if (quals & TYPE_QUAL_CONST)
|
||||
flags |= 1;
|
||||
if (quals & TYPE_QUAL_VOLATILE)
|
||||
flags |= 2;
|
||||
return flags;
|
||||
}
|
||||
|
||||
/* Return a CONSTRUCTOR for the common part of the type_info objects. This
|
||||
is the vtable pointer and NTBS name. */
|
||||
|
||||
static tree
|
||||
tinfo_base_init (desc, target)
|
||||
tree desc;
|
||||
tree target;
|
||||
{
|
||||
tree name_string = tinfo_name (target);
|
||||
tree init = NULL_TREE;
|
||||
|
||||
if (TINFO_VTABLE_DECL (desc))
|
||||
{
|
||||
tree vtbl_ptr = build_unary_op (ADDR_EXPR, TINFO_VTABLE_DECL (desc), 0);
|
||||
|
||||
init = tree_cons (NULL_TREE, vtbl_ptr, init);
|
||||
}
|
||||
|
||||
init = tree_cons (NULL_TREE, decay_conversion (name_string), init);
|
||||
|
||||
init = build (CONSTRUCTOR, NULL_TREE, NULL_TREE, nreverse(init));
|
||||
TREE_HAS_CONSTRUCTOR (init) = TREE_CONSTANT (init) = TREE_STATIC (init) = 1;
|
||||
init = tree_cons (NULL_TREE, init, NULL_TREE);
|
||||
|
||||
return init;
|
||||
}
|
||||
|
||||
/* Return the CONSTRUCTOR expr for a type_info of TYPE. DESC provides the
|
||||
information about the particular type_info derivation, which adds no
|
||||
additional fields to the type_info base. */
|
||||
|
||||
static tree
|
||||
generic_initializer (desc, target)
|
||||
tree desc;
|
||||
tree target;
|
||||
{
|
||||
tree init = tinfo_base_init (desc, target);
|
||||
|
||||
init = build (CONSTRUCTOR, NULL_TREE, NULL_TREE, init);
|
||||
TREE_HAS_CONSTRUCTOR (init) = TREE_CONSTANT (init) = TREE_STATIC (init) = 1;
|
||||
return init;
|
||||
}
|
||||
|
||||
/* Return the CONSTRUCTOR expr for a type_info of pointer or reference TYPE.
|
||||
DESC provides information about the particular type_info derivation,
|
||||
which adds target type and qualifier flags members to the type_info base. */
|
||||
|
||||
static tree
|
||||
ptr_ref_initializer (desc, target)
|
||||
tree desc;
|
||||
tree target;
|
||||
{
|
||||
tree init = tinfo_base_init (desc, target);
|
||||
tree to = TREE_TYPE (target);
|
||||
int flags = qualifier_flags (to);
|
||||
|
||||
init = tree_cons (NULL_TREE, build_int_2 (flags, 0), init);
|
||||
init = tree_cons (NULL_TREE,
|
||||
build_unary_op (ADDR_EXPR,
|
||||
get_tinfo_decl (TYPE_MAIN_VARIANT (to)), 0),
|
||||
init);
|
||||
|
||||
init = build (CONSTRUCTOR, NULL_TREE, NULL_TREE, nreverse (init));
|
||||
TREE_HAS_CONSTRUCTOR (init) = TREE_CONSTANT (init) = TREE_STATIC (init) = 1;
|
||||
return init;
|
||||
}
|
||||
|
||||
/* Return the CONSTRUCTOR expr for a type_info of pointer or reference TYPE.
|
||||
DESC provides information about the particular type_info derivation,
|
||||
which adds target type and qualifier flags members to the type_info base. */
|
||||
|
||||
static tree
|
||||
ptmd_initializer (desc, target)
|
||||
tree desc;
|
||||
tree target;
|
||||
{
|
||||
tree init = tinfo_base_init (desc, target);
|
||||
tree to = TYPE_PTRMEM_POINTED_TO_TYPE (target);
|
||||
tree klass = TYPE_PTRMEM_CLASS_TYPE (target);
|
||||
int flags = qualifier_flags (to);
|
||||
|
||||
init = tree_cons (NULL_TREE,
|
||||
build_unary_op (ADDR_EXPR, get_tinfo_decl (klass), 0),
|
||||
init);
|
||||
init = tree_cons (NULL_TREE,
|
||||
build_unary_op (ADDR_EXPR,
|
||||
get_tinfo_decl (TYPE_MAIN_VARIANT (to)), 0),
|
||||
init);
|
||||
init = tree_cons (NULL_TREE, build_int_2 (flags, 0), init);
|
||||
|
||||
init = build (CONSTRUCTOR, NULL_TREE, NULL_TREE, nreverse (init));
|
||||
TREE_HAS_CONSTRUCTOR (init) = TREE_CONSTANT (init) = TREE_STATIC (init) = 1;
|
||||
return init;
|
||||
}
|
||||
|
||||
/* Determine the hint flags describing the features of a class's heirarchy.
|
||||
FIXME: better set the hint_flags here! For now set them
|
||||
to safe 'don't know' values. The specification is under
|
||||
review. Don't forget to check the runtime dynamic_cast and
|
||||
catch machinery if these change. */
|
||||
|
||||
static int
|
||||
class_hint_flags (type)
|
||||
tree type;
|
||||
{
|
||||
int hint_flags = 0;
|
||||
hint_flags |= 0x1; /* contains multiply inherited sub object */
|
||||
hint_flags |= 0x4; /* has virtual bases */
|
||||
hint_flags |= 0x8; /* has private base */
|
||||
if (TYPE_POLYMORPHIC_P (type))
|
||||
hint_flags |= 0x2;
|
||||
|
||||
return hint_flags;
|
||||
}
|
||||
|
||||
/* Return the CONSTRUCTOR expr for a type_info of class TYPE.
|
||||
DESC provides information about the particular __class_type_info derivation,
|
||||
which adds hint flags and TRAIL initializers to the type_info base. */
|
||||
|
||||
static tree
|
||||
class_initializer (desc, target, trail)
|
||||
tree desc;
|
||||
tree target;
|
||||
tree trail;
|
||||
{
|
||||
tree init = tinfo_base_init (desc, target);
|
||||
int flags = class_hint_flags (target);
|
||||
|
||||
trail = tree_cons (NULL_TREE, build_int_2 (flags, 0), trail);
|
||||
TREE_CHAIN (init) = trail;
|
||||
init = build (CONSTRUCTOR, NULL_TREE, NULL_TREE, init);
|
||||
TREE_HAS_CONSTRUCTOR (init) = TREE_CONSTANT (init) = TREE_STATIC (init) = 1;
|
||||
return init;
|
||||
}
|
||||
|
||||
/* Generate a pseudo_type_info VAR_DECL suitable for the supplied
|
||||
TARGET_TYPE and given the REAL_NAME. This is the structure expected by
|
||||
the runtime, and therefore has additional fields. If we need not emit a
|
||||
definition (because the runtime must contain it), return NULL_TREE,
|
||||
otherwise return the VAR_DECL. */
|
||||
|
||||
static tree
|
||||
synthesize_tinfo_var (target_type, real_name)
|
||||
tree target_type;
|
||||
tree real_name;
|
||||
{
|
||||
tree var_init = NULL_TREE;
|
||||
tree var_type = NULL_TREE;
|
||||
|
||||
my_friendly_assert (new_abi_rtti_p (), 20000118);
|
||||
|
||||
switch (TREE_CODE (target_type))
|
||||
{
|
||||
case POINTER_TYPE:
|
||||
if (TYPE_PTRMEM_P (target_type))
|
||||
{
|
||||
var_type = ptmd_desc_type_node;
|
||||
var_init = ptmd_initializer (var_type, target_type);
|
||||
}
|
||||
else
|
||||
{
|
||||
int code = TREE_CODE (TREE_TYPE (target_type));
|
||||
|
||||
if ((CP_TYPE_QUALS (TREE_TYPE (target_type)) | TYPE_QUAL_CONST)
|
||||
== TYPE_QUAL_CONST
|
||||
&& (code == INTEGER_TYPE || code == BOOLEAN_TYPE
|
||||
|| code == CHAR_TYPE || code == REAL_TYPE
|
||||
|| code == VOID_TYPE)
|
||||
&& !doing_runtime)
|
||||
/* These are in the runtime. */
|
||||
return NULL_TREE;
|
||||
var_type = ptr_desc_type_node;
|
||||
var_init = ptr_ref_initializer (var_type, target_type);
|
||||
}
|
||||
break;
|
||||
case REFERENCE_TYPE:
|
||||
var_type = ref_desc_type_node;
|
||||
var_init = ptr_ref_initializer (var_type, target_type);
|
||||
break;
|
||||
case ENUMERAL_TYPE:
|
||||
var_type = enum_desc_type_node;
|
||||
var_init = generic_initializer (var_type, target_type);
|
||||
break;
|
||||
case FUNCTION_TYPE:
|
||||
var_type = func_desc_type_node;
|
||||
var_init = generic_initializer (var_type, target_type);
|
||||
break;
|
||||
case ARRAY_TYPE:
|
||||
var_type = ary_desc_type_node;
|
||||
var_init = generic_initializer (var_type, target_type);
|
||||
break;
|
||||
case UNION_TYPE:
|
||||
case RECORD_TYPE:
|
||||
if (!TYPE_SIZE (target_type))
|
||||
{
|
||||
/* FIXME: incomplete type. Awaiting specification. */
|
||||
return NULL_TREE;
|
||||
}
|
||||
else if (!CLASSTYPE_N_BASECLASSES (target_type))
|
||||
{
|
||||
var_type = class_desc_type_node;
|
||||
var_init = class_initializer (var_type, target_type, NULL_TREE);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* if this has a single public non-virtual base, it's easier */
|
||||
tree binfo = TYPE_BINFO (target_type);
|
||||
int nbases = BINFO_N_BASETYPES (binfo);
|
||||
tree base_binfos = BINFO_BASETYPES (binfo);
|
||||
tree base_inits = NULL_TREE;
|
||||
int is_simple = nbases == 1;
|
||||
int ix;
|
||||
|
||||
/* Generate the base information initializer. */
|
||||
for (ix = nbases; ix--;)
|
||||
{
|
||||
tree base_binfo = TREE_VEC_ELT (base_binfos, ix);
|
||||
tree base_init = NULL_TREE;
|
||||
int flags = 0;
|
||||
tree tinfo;
|
||||
tree offset;
|
||||
|
||||
if (TREE_VIA_VIRTUAL (base_binfo))
|
||||
flags |= 1;
|
||||
if (TREE_PUBLIC (base_binfo))
|
||||
flags |= 2;
|
||||
tinfo = get_tinfo_decl (BINFO_TYPE (base_binfo));
|
||||
tinfo = build_unary_op (ADDR_EXPR, tinfo, 0);
|
||||
offset = get_base_offset (base_binfo, target_type);
|
||||
|
||||
/* is it a single public inheritance? */
|
||||
if (is_simple && flags == 2 && integer_zerop (offset))
|
||||
{
|
||||
base_inits = tree_cons (NULL_TREE, tinfo, NULL_TREE);
|
||||
break;
|
||||
}
|
||||
is_simple = 0;
|
||||
|
||||
base_init = tree_cons
|
||||
(NULL_TREE, build_int_2 (flags, 0), base_init);
|
||||
base_init = tree_cons (NULL_TREE, offset, base_init);
|
||||
base_init = tree_cons (NULL_TREE, tinfo, base_init);
|
||||
base_init = build (CONSTRUCTOR, NULL_TREE, NULL_TREE, base_init);
|
||||
base_inits = tree_cons (NULL_TREE, base_init, base_inits);
|
||||
}
|
||||
|
||||
if (is_simple)
|
||||
var_type = si_class_desc_type_node;
|
||||
else
|
||||
{
|
||||
/* Prepend the number of bases. */
|
||||
base_inits = build (CONSTRUCTOR, NULL_TREE, NULL_TREE, base_inits);
|
||||
base_inits = tree_cons (NULL_TREE, base_inits, NULL_TREE);
|
||||
base_inits = tree_cons (NULL_TREE,
|
||||
build_int_2 (nbases, 0), base_inits);
|
||||
|
||||
var_type = get_vmi_pseudo_type_info (nbases);
|
||||
}
|
||||
var_init = class_initializer (var_type, target_type, base_inits);
|
||||
}
|
||||
break;
|
||||
case INTEGER_TYPE:
|
||||
case BOOLEAN_TYPE:
|
||||
case CHAR_TYPE:
|
||||
case REAL_TYPE:
|
||||
case VOID_TYPE:
|
||||
if (!doing_runtime)
|
||||
/* These are guaranteed to be in the runtime. */
|
||||
return NULL_TREE;
|
||||
var_type = bltn_desc_type_node;
|
||||
var_init = generic_initializer (var_type, target_type);
|
||||
break;
|
||||
default:
|
||||
my_friendly_abort (20000117);
|
||||
}
|
||||
|
||||
return create_real_tinfo_var (real_name, TINFO_PSEUDO_TYPE (var_type), var_init);
|
||||
}
|
||||
|
||||
/* Create the real typeinfo variable. */
|
||||
|
||||
static tree
|
||||
create_real_tinfo_var (name, type, init)
|
||||
tree name;
|
||||
tree type;
|
||||
tree init;
|
||||
{
|
||||
tree decl;
|
||||
|
||||
decl = build_lang_decl (VAR_DECL, name,
|
||||
build_qualified_type (type, TYPE_QUAL_CONST));
|
||||
DECL_ARTIFICIAL (decl) = 1;
|
||||
TREE_READONLY (decl) = 1;
|
||||
TREE_STATIC (decl) = 1;
|
||||
TREE_PUBLIC (decl) = 1;
|
||||
DECL_EXTERNAL (decl) = 0;
|
||||
|
||||
comdat_linkage (decl);
|
||||
DECL_ASSEMBLER_NAME (decl) = name;
|
||||
DECL_INITIAL (decl) = init;
|
||||
cp_finish_decl (decl, init, NULL_TREE, 0);
|
||||
|
||||
return decl;
|
||||
}
|
||||
|
||||
/* Generate the RECORD_TYPE containing the data layout of a type_info
|
||||
derivative as used by the runtime. This layout must be consistent with
|
||||
that defined in the runtime support. Also generate the VAR_DECL for the
|
||||
type's vtable. We explicitly manage the vtable member, and name it for
|
||||
real type as used in the runtime. The RECORD type has a different name,
|
||||
to avoid collisions. Return a TREE_LIST who's TINFO_PSEUDO_TYPE
|
||||
is the generated type and TINFO_VTABLE_DECL is the vtable decl.
|
||||
|
||||
REAL_NAME is the runtime's name of the type. Trailing arguments are
|
||||
additional FIELD_DECL's for the structure. The final argument must be
|
||||
NULL. */
|
||||
|
||||
static tree
|
||||
create_pseudo_type_info VPARAMS((const char *real_name, int ident, ...))
|
||||
{
|
||||
#ifndef ANSI_PROTOTYPES
|
||||
char const *real_name;
|
||||
int ident;
|
||||
#endif
|
||||
va_list ap;
|
||||
tree real_type, pseudo_type;
|
||||
char *pseudo_name;
|
||||
tree vtable_decl;
|
||||
int ix;
|
||||
tree fields[10];
|
||||
tree field_decl;
|
||||
tree result;
|
||||
|
||||
VA_START (ap, ident);
|
||||
#ifndef ANSI_PROTOTYPES
|
||||
real_name = va_arg (ap, char const *);
|
||||
ident = va_arg (app, int);
|
||||
#endif
|
||||
|
||||
/* Generate the pseudo type name. */
|
||||
pseudo_name = (char *)alloca (strlen (real_name) + 30);
|
||||
strcpy (pseudo_name, real_name);
|
||||
strcat (pseudo_name, "_pseudo");
|
||||
if (ident)
|
||||
sprintf (pseudo_name + strlen (pseudo_name), "%d", ident);
|
||||
|
||||
/* Get the vtable decl. */
|
||||
real_type = xref_tag (class_type_node, get_identifier (real_name), 1);
|
||||
vtable_decl = get_vtable_decl (real_type, /*complete=*/1);
|
||||
|
||||
/* First field is the pseudo type_info base class. */
|
||||
fields[0] = build_lang_decl (FIELD_DECL, NULL_TREE, ti_desc_type_node);
|
||||
|
||||
/* Now add the derived fields. */
|
||||
for (ix = 0; (field_decl = va_arg (ap, tree));)
|
||||
fields[++ix] = field_decl;
|
||||
|
||||
/* Create the pseudo type. */
|
||||
pseudo_type = make_aggr_type (RECORD_TYPE);
|
||||
finish_builtin_type (pseudo_type, pseudo_name, fields, ix, ptr_type_node);
|
||||
TYPE_HAS_CONSTRUCTOR (pseudo_type) = 1;
|
||||
va_end (ap);
|
||||
|
||||
result = tree_cons (NULL_TREE, NULL_TREE, NULL_TREE);
|
||||
TINFO_VTABLE_DECL (result) = vtable_decl;
|
||||
TINFO_PSEUDO_TYPE (result) = pseudo_type;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Return a descriptor for a vmi type with NUM_BASES bases. */
|
||||
|
||||
static tree
|
||||
get_vmi_pseudo_type_info (num_bases)
|
||||
int num_bases;
|
||||
{
|
||||
tree desc;
|
||||
tree array_domain, base_array;
|
||||
|
||||
if (TREE_VEC_LENGTH (vmi_class_desc_type_node) <= num_bases)
|
||||
{
|
||||
int ix;
|
||||
tree extend = make_tree_vec (num_bases + 5);
|
||||
|
||||
for (ix = TREE_VEC_LENGTH (vmi_class_desc_type_node); ix--;)
|
||||
TREE_VEC_ELT (extend, ix) = TREE_VEC_ELT (vmi_class_desc_type_node, ix);
|
||||
vmi_class_desc_type_node = extend;
|
||||
}
|
||||
desc = TREE_VEC_ELT (vmi_class_desc_type_node, num_bases);
|
||||
|
||||
if (desc)
|
||||
return desc;
|
||||
|
||||
/* Add number of bases and trailing array of base_class_type_info. */
|
||||
array_domain = build_index_type (build_int_2 (num_bases, 0));
|
||||
base_array = build_array_type (base_desc_type_node, array_domain);
|
||||
|
||||
desc = create_pseudo_type_info
|
||||
("__vmi_class_type_info", num_bases,
|
||||
build_lang_decl (FIELD_DECL, NULL_TREE, integer_type_node),
|
||||
build_lang_decl (FIELD_DECL, NULL_TREE, integer_type_node),
|
||||
build_lang_decl (FIELD_DECL, NULL_TREE, base_array),
|
||||
NULL);
|
||||
TREE_VEC_ELT (vmi_class_desc_type_node, num_bases) = desc;
|
||||
return desc;
|
||||
}
|
||||
|
||||
/* Make sure the required builtin types exist for generating the type_info
|
||||
varable definitions. */
|
||||
|
||||
static void
|
||||
create_tinfo_types ()
|
||||
{
|
||||
tree ptr_type_info;
|
||||
|
||||
if (bltn_desc_type_node)
|
||||
return;
|
||||
if (flag_honor_std)
|
||||
push_namespace (get_identifier ("std"));
|
||||
|
||||
ptr_type_info = build_pointer_type
|
||||
(build_qualified_type
|
||||
(type_info_type_node, TYPE_QUAL_CONST));
|
||||
|
||||
/* Create the internal type_info structure. This is used as a base for
|
||||
the other structures. */
|
||||
{
|
||||
tree fields[2];
|
||||
|
||||
ti_desc_type_node = make_aggr_type (RECORD_TYPE);
|
||||
fields[0] = build_lang_decl (FIELD_DECL, NULL_TREE, const_ptr_type_node);
|
||||
fields[1] = build_lang_decl (FIELD_DECL, NULL_TREE, const_string_type_node);
|
||||
finish_builtin_type (ti_desc_type_node, "__type_info_pseudo",
|
||||
fields, 1, ptr_type_node);
|
||||
TYPE_HAS_CONSTRUCTOR (ti_desc_type_node) = 1;
|
||||
}
|
||||
|
||||
/* Fundamental type_info */
|
||||
bltn_desc_type_node = create_pseudo_type_info
|
||||
("__fundamental_type_info", 0,
|
||||
NULL);
|
||||
|
||||
/* Pointer and reference type_info. These two fields, qualification mask
|
||||
and pointer to the pointed to (referenced) type. */
|
||||
ptr_desc_type_node = create_pseudo_type_info
|
||||
("__pointer_type_info", 0,
|
||||
build_lang_decl (FIELD_DECL, NULL_TREE, integer_type_node),
|
||||
build_lang_decl (FIELD_DECL, NULL_TREE, ptr_type_info),
|
||||
NULL);
|
||||
ref_desc_type_node = create_pseudo_type_info
|
||||
("__reference_type_info", 0,
|
||||
build_lang_decl (FIELD_DECL, NULL_TREE, integer_type_node),
|
||||
build_lang_decl (FIELD_DECL, NULL_TREE, ptr_type_info),
|
||||
NULL);
|
||||
|
||||
/* Array, function and enum type_info. No additional fields. */
|
||||
ary_desc_type_node = create_pseudo_type_info
|
||||
("__array_type_info", 0,
|
||||
NULL);
|
||||
func_desc_type_node = create_pseudo_type_info
|
||||
("__function_type_info", 0,
|
||||
NULL);
|
||||
enum_desc_type_node = create_pseudo_type_info
|
||||
("__enum_type_info", 0,
|
||||
NULL);
|
||||
|
||||
/* Class type_info. Add a flags field. */
|
||||
class_desc_type_node = create_pseudo_type_info
|
||||
("__class_type_info", 0,
|
||||
build_lang_decl (FIELD_DECL, NULL_TREE, integer_type_node),
|
||||
NULL);
|
||||
|
||||
/* Single public non-virtual base class. Add pointer to base class. */
|
||||
si_class_desc_type_node = create_pseudo_type_info
|
||||
("__si_class_type_info", 0,
|
||||
build_lang_decl (FIELD_DECL, NULL_TREE, integer_type_node),
|
||||
build_lang_decl (FIELD_DECL, NULL_TREE, ptr_type_info),
|
||||
NULL);
|
||||
|
||||
/* Base class internal helper. Pointer to base type, offset to base,
|
||||
flags. */
|
||||
{
|
||||
tree fields[3];
|
||||
|
||||
fields[0] = build_lang_decl (FIELD_DECL, NULL_TREE, ptr_type_info),
|
||||
fields[1] = build_lang_decl (FIELD_DECL, NULL_TREE, ptrdiff_type_node),
|
||||
fields[2] = build_lang_decl (FIELD_DECL, NULL_TREE, integer_type_node),
|
||||
base_desc_type_node = make_aggr_type (RECORD_TYPE);
|
||||
finish_builtin_type (base_desc_type_node, "__base_class_type_info_pseudo",
|
||||
fields, 2, ptr_type_node);
|
||||
TYPE_HAS_CONSTRUCTOR (base_desc_type_node) = 1;
|
||||
}
|
||||
|
||||
/* General heirarchy is created as necessary in this vector. */
|
||||
vmi_class_desc_type_node = make_tree_vec (10);
|
||||
|
||||
/* Pointer to member data type_info. Add pointer to the class, pointer
|
||||
to the member's type info and qualifications flags. */
|
||||
ptmd_desc_type_node = create_pseudo_type_info
|
||||
("__ptr_to_member_type_info", 0,
|
||||
build_lang_decl (FIELD_DECL, NULL_TREE, ptr_type_info),
|
||||
build_lang_decl (FIELD_DECL, NULL_TREE, ptr_type_info),
|
||||
build_lang_decl (FIELD_DECL, NULL_TREE, integer_type_node),
|
||||
NULL);
|
||||
|
||||
if (flag_honor_std)
|
||||
pop_namespace ();
|
||||
}
|
||||
|
||||
/* Emit the type_info descriptors which are guaranteed to be in the runtime
|
||||
support. Generating them here guarantees consistency with the other
|
||||
structures. We use the following heuristic to determine when the runtime
|
||||
is being generated. If std::__fundamental_type_info is defined, and it's
|
||||
destructor is defined, then the runtime is being built. */
|
||||
|
||||
void
|
||||
emit_support_tinfos ()
|
||||
{
|
||||
static tree *const fundamentals[] =
|
||||
{
|
||||
&void_type_node,
|
||||
&boolean_type_node,
|
||||
&wchar_type_node,
|
||||
#if 0
|
||||
&signed_wchar_type_node, &unsigned_wchar_type_node,
|
||||
#endif
|
||||
&char_type_node, &signed_char_type_node, &unsigned_char_type_node,
|
||||
&short_integer_type_node, &short_unsigned_type_node,
|
||||
&integer_type_node, &unsigned_type_node,
|
||||
&long_integer_type_node, &long_unsigned_type_node,
|
||||
&long_long_integer_type_node, &long_long_unsigned_type_node,
|
||||
&float_type_node, &double_type_node, &long_double_type_node,
|
||||
|
||||
/* GCC extension types */
|
||||
#if 0
|
||||
&complex_integer_type_node,
|
||||
&complex_float_type_node, &complex_double_type_node,
|
||||
&complex_long_double_type_node,
|
||||
#endif
|
||||
|
||||
0
|
||||
};
|
||||
int ix;
|
||||
tree bltn_type, dtor;
|
||||
|
||||
if (flag_honor_std)
|
||||
push_namespace (get_identifier ("std"));
|
||||
bltn_type = xref_tag (class_type_node,
|
||||
get_identifier ("__fundamental_type_info"), 1);
|
||||
if (flag_honor_std)
|
||||
pop_namespace ();
|
||||
if (!TYPE_SIZE (bltn_type))
|
||||
return;
|
||||
dtor = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (bltn_type), 1);
|
||||
if (DECL_EXTERNAL (dtor))
|
||||
return;
|
||||
doing_runtime = 1;
|
||||
for (ix = 0; fundamentals[ix]; ix++)
|
||||
{
|
||||
tree bltn = *fundamentals[ix];
|
||||
tree bltn_ptr = build_pointer_type (bltn);
|
||||
tree bltn_const_ptr = build_pointer_type
|
||||
(build_qualified_type (bltn, TYPE_QUAL_CONST));
|
||||
tree tinfo;
|
||||
|
||||
tinfo = get_tinfo_decl (bltn);
|
||||
TREE_USED (tinfo) = 1;
|
||||
TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (tinfo)) = 1;
|
||||
|
||||
tinfo = get_tinfo_decl (bltn_ptr);
|
||||
TREE_USED (tinfo) = 1;
|
||||
TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (tinfo)) = 1;
|
||||
|
||||
tinfo = get_tinfo_decl (bltn_const_ptr);
|
||||
TREE_USED (tinfo) = 1;
|
||||
TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (tinfo)) = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return non-zero, iff T is a type_info variable which has not had a
|
||||
definition emitted for it. */
|
||||
|
||||
int
|
||||
tinfo_decl_p (t, data)
|
||||
tree t;
|
||||
void *data ATTRIBUTE_UNUSED;
|
||||
{
|
||||
return TREE_CODE (t) == VAR_DECL
|
||||
&& IDENTIFIER_GLOBAL_VALUE (DECL_NAME (t)) == (t)
|
||||
&& TREE_TYPE (t) == tinfo_decl_type
|
||||
&& TREE_TYPE (DECL_NAME (t));
|
||||
}
|
||||
|
||||
/* Emit a suitable type_info definition for the type_info decl pointed to by
|
||||
DECL_PTR. We emit a completely new variable, of the correct type for the
|
||||
actual type this is describing. The DECL_ASSEMBLER_NAME of the generated
|
||||
definition is set to that of the supplied decl, so that they can be tied
|
||||
up. Mark the supplied decl as having been dealt with. Emitting one
|
||||
definitions might cause other declarations to be emitted.
|
||||
|
||||
We need to do things this way, because we're trying to do something like
|
||||
|
||||
struct B : A {
|
||||
...
|
||||
};
|
||||
|
||||
extern const A tinfo_var;
|
||||
|
||||
const B tinfo_var = {...};
|
||||
|
||||
which is not permitted. Also, we've not necessarily seen the definition of B.
|
||||
So we do something like the following,
|
||||
|
||||
extern const A tinfo_var;
|
||||
|
||||
struct pseudo_A {
|
||||
const void *vtable_ptr;
|
||||
const char *name;
|
||||
};
|
||||
struct pseudo_B {
|
||||
pseudo_A base;
|
||||
...
|
||||
};
|
||||
|
||||
const pseudo_B proxy_tinfo_var attribute((assembler_name="tinfo_var")) =
|
||||
{
|
||||
{&B::vtable, "..."},
|
||||
...
|
||||
};
|
||||
|
||||
pseudo_A and pseudo_B must be layout equivalent to the real definitions in
|
||||
the runtime. */
|
||||
|
||||
int
|
||||
emit_tinfo_decl (decl_ptr, data)
|
||||
tree *decl_ptr;
|
||||
void *data ATTRIBUTE_UNUSED;
|
||||
{
|
||||
tree tinfo_decl = *decl_ptr;
|
||||
tree tinfo_type, decl;
|
||||
|
||||
my_friendly_assert (TREE_TYPE (tinfo_decl) == tinfo_decl_type, 20000121);
|
||||
tinfo_type = TREE_TYPE (DECL_NAME (tinfo_decl));
|
||||
my_friendly_assert (tinfo_type != NULL_TREE, 20000120);
|
||||
|
||||
/* Say we've dealt with it. */
|
||||
TREE_TYPE (DECL_NAME (tinfo_decl)) = NULL_TREE;
|
||||
|
||||
if (!DECL_NEEDED_P (tinfo_decl))
|
||||
return 0;
|
||||
create_tinfo_types ();
|
||||
decl = synthesize_tinfo_var (tinfo_type, DECL_ASSEMBLER_NAME (tinfo_decl));
|
||||
|
||||
return decl != 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user