#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "tree.h"
#include "cp-tree.h"
#include "flags.h"
#include "output.h"
#include "assert.h"
#include "toplev.h"
#include "convert.h"
#define TINFO_PSEUDO_TYPE(NODE) TREE_TYPE (NODE)
#define TINFO_VTABLE_DECL(NODE) TREE_VALUE (NODE)
#define TINFO_REAL_NAME(NODE) TREE_PURPOSE (NODE)
VEC (tree) *unemitted_tinfo_decls;
static tree build_headof (tree);
static tree ifnonnull (tree, tree);
static tree tinfo_name (tree);
static tree build_dynamic_cast_1 (tree, tree);
static tree throw_bad_cast (void);
static tree throw_bad_typeid (void);
static tree get_tinfo_decl_dynamic (tree);
static tree get_tinfo_ptr (tree);
static bool typeid_ok_p (void);
static int qualifier_flags (tree);
static bool target_incomplete_p (tree);
static tree tinfo_base_init (tree, tree);
static tree generic_initializer (tree, tree);
static tree class_initializer (tree, tree, tree);
static tree create_pseudo_type_info (const char *, int, ...);
static tree get_pseudo_ti_init (tree, tree);
static tree get_pseudo_ti_desc (tree);
static void create_tinfo_types (void);
static bool typeinfo_in_lib_p (tree);
static int doing_runtime = 0;
void
init_rtti_processing (void)
{
tree type_info_type;
push_namespace (std_identifier);
type_info_type = xref_tag (class_type, get_identifier ("type_info"),
ts_global, false);
pop_namespace ();
const_type_info_type_node
= build_qualified_type (type_info_type, TYPE_QUAL_CONST);
type_info_ptr_type = build_pointer_type (const_type_info_type_node);
unemitted_tinfo_decls = VEC_alloc (tree, 124);
create_tinfo_types ();
}
static tree
build_headof (tree exp)
{
tree type = TREE_TYPE (exp);
tree offset;
tree index;
gcc_assert (TREE_CODE (type) == POINTER_TYPE);
type = TREE_TYPE (type);
if (!TYPE_POLYMORPHIC_P (type))
return exp;
exp = save_expr (exp);
index = build_int_cst (NULL_TREE,
-2 * TARGET_VTABLE_DATA_ENTRY_DISTANCE);
offset = build_vtbl_ref (build_indirect_ref (exp, NULL), index);
type = build_qualified_type (ptr_type_node,
cp_type_quals (TREE_TYPE (exp)));
return build2 (PLUS_EXPR, type, exp,
convert_to_integer (ptrdiff_type_node, offset));
}
static tree
throw_bad_cast (void)
{
tree fn = get_identifier ("__cxa_bad_cast");
if (!get_global_value_if_present (fn, &fn))
fn = push_throw_library_fn (fn, build_function_type (ptr_type_node,
void_list_node));
return build_cxx_call (fn, NULL_TREE);
}
static tree
throw_bad_typeid (void)
{
tree fn = get_identifier ("__cxa_bad_typeid");
if (!get_global_value_if_present (fn, &fn))
{
tree t;
t = build_reference_type (const_type_info_type_node);
t = build_function_type (t, void_list_node);
fn = push_throw_library_fn (fn, t);
}
return build_cxx_call (fn, NULL_TREE);
}
static tree
get_tinfo_decl_dynamic (tree exp)
{
tree type;
tree t;
if (exp == error_mark_node)
return error_mark_node;
type = non_reference (TREE_TYPE (exp));
type = TYPE_MAIN_VARIANT (type);
if (!VOID_TYPE_P (type))
type = complete_type_or_else (type, exp);
if (!type)
return error_mark_node;
if (TYPE_POLYMORPHIC_P (type) && ! resolves_to_fixed_type_p (exp, 0))
{
tree index;
index = build_int_cst (NULL_TREE,
-1 * TARGET_VTABLE_DATA_ENTRY_DISTANCE);
t = build_vtbl_ref (exp, index);
t = convert (type_info_ptr_type, t);
}
else
t = get_tinfo_ptr (TYPE_MAIN_VARIANT (type));
return build_indirect_ref (t, NULL);
}
static bool
typeid_ok_p (void)
{
if (! flag_rtti)
{
error ("cannot use typeid with -fno-rtti");
return false;
}
if (!COMPLETE_TYPE_P (const_type_info_type_node))
{
error ("must #include <typeinfo> before using typeid");
return false;
}
return true;
}
tree
build_typeid (tree exp)
{
tree cond = NULL_TREE;
int nonnull = 0;
if (exp == error_mark_node || !typeid_ok_p ())
return error_mark_node;
if (processing_template_decl)
return build_min (TYPEID_EXPR, const_type_info_type_node, exp);
if (TREE_CODE (exp) == INDIRECT_REF
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == POINTER_TYPE
&& TYPE_POLYMORPHIC_P (TREE_TYPE (exp))
&& ! resolves_to_fixed_type_p (exp, &nonnull)
&& ! nonnull)
{
exp = stabilize_reference (exp);
cond = cp_convert (boolean_type_node, TREE_OPERAND (exp, 0));
}
exp = get_tinfo_decl_dynamic (exp);
if (exp == error_mark_node)
return error_mark_node;
if (cond)
{
tree bad = throw_bad_typeid ();
exp = build3 (COND_EXPR, TREE_TYPE (exp), cond, exp, bad);
}
return exp;
}
static tree
tinfo_name (tree type)
{
const char *name;
tree name_string;
name = mangle_type_string (type);
name_string = fix_string_type (build_string (strlen (name) + 1, name));
return name_string;
}
tree
get_tinfo_decl (tree type)
{
tree name;
tree d;
if (COMPLETE_TYPE_P (type)
&& TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
{
error ("cannot create type information for type %qT because "
"its size is variable",
type);
return error_mark_node;
}
if (TREE_CODE (type) == METHOD_TYPE)
type = build_function_type (TREE_TYPE (type),
TREE_CHAIN (TYPE_ARG_TYPES (type)));
if (CLASS_TYPE_P (type))
{
d = CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (type));
if (d)
return d;
}
name = mangle_typeinfo_for_type (type);
d = IDENTIFIER_GLOBAL_VALUE (name);
if (!d)
{
tree var_desc = get_pseudo_ti_desc (type);
d = build_lang_decl (VAR_DECL, name, TINFO_PSEUDO_TYPE (var_desc));
SET_DECL_ASSEMBLER_NAME (d, name);
TREE_TYPE (name) = type;
DECL_TINFO_P (d) = 1;
DECL_ARTIFICIAL (d) = 1;
DECL_IGNORED_P (d) = 1;
TREE_READONLY (d) = 1;
TREE_STATIC (d) = 1;
DECL_EXTERNAL (d) = 1;
DECL_NOT_REALLY_EXTERN (d) = 1;
if (CLASS_TYPE_P (type))
CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (type)) = d;
set_linkage_according_to_type (type, d);
pushdecl_top_level_and_finish (d, NULL_TREE);
VEC_safe_push (tree, unemitted_tinfo_decls, d);
}
return d;
}
static tree
get_tinfo_ptr (tree type)
{
tree decl = get_tinfo_decl (type);
mark_used (decl);
return build_nop (type_info_ptr_type,
build_address (decl));
}
tree
get_typeid (tree type)
{
if (type == error_mark_node || !typeid_ok_p ())
return error_mark_node;
if (processing_template_decl)
return build_min (TYPEID_EXPR, const_type_info_type_node, type);
type = non_reference (type);
type = TYPE_MAIN_VARIANT (type);
if (!VOID_TYPE_P (type))
type = complete_type_or_else (type, NULL_TREE);
if (!type)
return error_mark_node;
return build_indirect_ref (get_tinfo_ptr (type), NULL);
}
static tree
ifnonnull (tree test, tree result)
{
return build3 (COND_EXPR, TREE_TYPE (result),
build2 (EQ_EXPR, boolean_type_node, test, integer_zero_node),
cp_convert (TREE_TYPE (result), integer_zero_node),
result);
}
static tree
build_dynamic_cast_1 (tree type, tree expr)
{
enum tree_code tc = TREE_CODE (type);
tree exprtype = TREE_TYPE (expr);
tree dcast_fn;
tree old_expr = expr;
const char *errstr = NULL;
switch (tc)
{
case POINTER_TYPE:
if (TREE_CODE (TREE_TYPE (type)) == VOID_TYPE)
break;
case REFERENCE_TYPE:
if (! IS_AGGR_TYPE (TREE_TYPE (type)))
{
errstr = "target is not pointer or reference to class";
goto fail;
}
if (!COMPLETE_TYPE_P (complete_type (TREE_TYPE (type))))
{
errstr = "target is not pointer or reference to complete type";
goto fail;
}
break;
default:
errstr = "target is not pointer or reference";
goto fail;
}
if (tc == POINTER_TYPE)
{
if (TREE_CODE (exprtype) != POINTER_TYPE)
{
errstr = "source is not a pointer";
goto fail;
}
if (! IS_AGGR_TYPE (TREE_TYPE (exprtype)))
{
errstr = "source is not a pointer to class";
goto fail;
}
if (!COMPLETE_TYPE_P (complete_type (TREE_TYPE (exprtype))))
{
errstr = "source is a pointer to incomplete type";
goto fail;
}
}
else
{
exprtype = build_reference_type (exprtype);
expr = convert_to_reference (exprtype, expr, CONV_IMPLICIT,
LOOKUP_NORMAL, NULL_TREE);
if (! IS_AGGR_TYPE (TREE_TYPE (exprtype)))
{
errstr = "source is not of class type";
goto fail;
}
if (!COMPLETE_TYPE_P (complete_type (TREE_TYPE (exprtype))))
{
errstr = "source is of incomplete class type";
goto fail;
}
}
if (!at_least_as_qualified_p (TREE_TYPE (type),
TREE_TYPE (exprtype)))
{
errstr = "conversion casts away constness";
goto fail;
}
{
tree binfo;
binfo = lookup_base (TREE_TYPE (exprtype), TREE_TYPE (type),
ba_check, NULL);
if (binfo)
{
expr = build_base_path (PLUS_EXPR, convert_from_reference (expr),
binfo, 0);
if (TREE_CODE (exprtype) == POINTER_TYPE)
expr = non_lvalue (expr);
return expr;
}
}
if (TYPE_POLYMORPHIC_P (TREE_TYPE (exprtype)))
{
tree expr1;
if (tc == POINTER_TYPE && VOID_TYPE_P (TREE_TYPE (type)))
{
if (TREE_CODE (expr) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (expr, 0)) == VAR_DECL
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == RECORD_TYPE)
return build1 (NOP_EXPR, type, expr);
expr = save_expr (expr);
expr1 = build_headof (expr);
if (TREE_TYPE (expr1) != type)
expr1 = build1 (NOP_EXPR, type, expr1);
return ifnonnull (expr, expr1);
}
else
{
tree retval;
tree result, td2, td3, elems;
tree static_type, target_type, boff;
if (tc == REFERENCE_TYPE)
{
if (TREE_CODE (old_expr) == VAR_DECL
&& TREE_CODE (TREE_TYPE (old_expr)) == RECORD_TYPE)
{
tree expr = throw_bad_cast ();
warning ("dynamic_cast of %q#D to %q#T can never succeed",
old_expr, type);
TREE_TYPE (expr) = type;
return expr;
}
}
else if (TREE_CODE (expr) == ADDR_EXPR)
{
tree op = TREE_OPERAND (expr, 0);
if (TREE_CODE (op) == VAR_DECL
&& TREE_CODE (TREE_TYPE (op)) == RECORD_TYPE)
{
warning ("dynamic_cast of %q#D to %q#T can never succeed",
op, type);
retval = build_int_cst (type, 0);
return retval;
}
}
target_type = TYPE_MAIN_VARIANT (TREE_TYPE (type));
static_type = TYPE_MAIN_VARIANT (TREE_TYPE (exprtype));
td2 = get_tinfo_decl (target_type);
mark_used (td2);
td2 = build_unary_op (ADDR_EXPR, td2, 0);
td3 = get_tinfo_decl (static_type);
mark_used (td3);
td3 = build_unary_op (ADDR_EXPR, td3, 0);
boff = dcast_base_hint (static_type, target_type);
expr = save_expr (expr);
expr1 = expr;
if (tc == REFERENCE_TYPE)
expr1 = build_unary_op (ADDR_EXPR, expr1, 0);
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;
tree ns = abi_node;
const char *name;
push_nested_namespace (ns);
tinfo_ptr = xref_tag (class_type,
get_identifier ("__class_type_info"),
ts_global, false);
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_library_fn_ptr (name, tmp);
DECL_IS_PURE (dcast_fn) = 1;
pop_nested_namespace (ns);
dynamic_cast_node = dcast_fn;
}
result = build_cxx_call (dcast_fn, elems);
if (tc == REFERENCE_TYPE)
{
tree bad = throw_bad_cast ();
result = save_expr (result);
return build3 (COND_EXPR, type, result, result, bad);
}
result = cp_convert (type, result);
return ifnonnull (expr, result);
}
}
else
errstr = "source type is not polymorphic";
fail:
error ("cannot dynamic_cast %qE (of type %q#T) to type %q#T (%s)",
expr, exprtype, type, errstr);
return error_mark_node;
}
tree
build_dynamic_cast (tree type, tree expr)
{
if (type == error_mark_node || expr == error_mark_node)
return error_mark_node;
if (processing_template_decl)
{
expr = build_min (DYNAMIC_CAST_EXPR, type, expr);
TREE_SIDE_EFFECTS (expr) = 1;
return expr;
}
return convert_from_reference (build_dynamic_cast_1 (type, expr));
}
static int
qualifier_flags (tree type)
{
int flags = 0;
int quals = cp_type_quals (type);
if (quals & TYPE_QUAL_CONST)
flags |= 1;
if (quals & TYPE_QUAL_VOLATILE)
flags |= 2;
if (quals & TYPE_QUAL_RESTRICT)
flags |= 4;
return flags;
}
static bool
target_incomplete_p (tree type)
{
while (true)
if (TYPE_PTRMEM_P (type))
{
if (!COMPLETE_TYPE_P (TYPE_PTRMEM_CLASS_TYPE (type)))
return true;
type = TYPE_PTRMEM_POINTED_TO_TYPE (type);
}
else if (TREE_CODE (type) == POINTER_TYPE)
type = TREE_TYPE (type);
else
return !COMPLETE_OR_VOID_TYPE_P (type);
}
static bool
involves_incomplete_p (tree type)
{
switch (TREE_CODE (type))
{
case POINTER_TYPE:
return target_incomplete_p (TREE_TYPE (type));
case OFFSET_TYPE:
ptrmem:
return
(target_incomplete_p (TYPE_PTRMEM_POINTED_TO_TYPE (type))
|| !COMPLETE_TYPE_P (TYPE_PTRMEM_CLASS_TYPE (type)));
case RECORD_TYPE:
if (TYPE_PTRMEMFUNC_P (type))
goto ptrmem;
case UNION_TYPE:
if (!COMPLETE_TYPE_P (type))
return true;
default:
return false;
}
}
static tree
tinfo_base_init (tree desc, tree target)
{
tree init = NULL_TREE;
tree name_decl;
tree vtable_ptr;
{
tree name_name;
tree name_type = build_cplus_array_type
(build_qualified_type (char_type_node, TYPE_QUAL_CONST),
NULL_TREE);
tree name_string = tinfo_name (target);
name_name = mangle_typeinfo_string_for_type (target);
TREE_TYPE (name_name) = target;
name_decl = build_lang_decl (VAR_DECL, name_name, name_type);
SET_DECL_ASSEMBLER_NAME (name_decl, name_name);
DECL_ARTIFICIAL (name_decl) = 1;
DECL_IGNORED_P (name_decl) = 1;
TREE_READONLY (name_decl) = 1;
TREE_STATIC (name_decl) = 1;
DECL_EXTERNAL (name_decl) = 0;
DECL_TINFO_P (name_decl) = 1;
if (involves_incomplete_p (target))
{
TREE_PUBLIC (name_decl) = 0;
DECL_INTERFACE_KNOWN (name_decl) = 1;
}
else
set_linkage_according_to_type (target, name_decl);
import_export_decl (name_decl);
DECL_INITIAL (name_decl) = name_string;
mark_used (name_decl);
pushdecl_top_level_and_finish (name_decl, name_string);
}
vtable_ptr = TINFO_VTABLE_DECL (desc);
if (!vtable_ptr)
{
tree real_type;
push_nested_namespace (abi_node);
real_type = xref_tag (class_type, TINFO_REAL_NAME (desc),
ts_global, false);
pop_nested_namespace (abi_node);
if (!COMPLETE_TYPE_P (real_type))
{
SET_CLASSTYPE_INTERFACE_KNOWN (real_type);
CLASSTYPE_INTERFACE_ONLY (real_type) = 1;
}
vtable_ptr = get_vtable_decl (real_type, 1);
vtable_ptr = build_unary_op (ADDR_EXPR, vtable_ptr, 0);
vtable_ptr = build2
(PLUS_EXPR, TREE_TYPE (vtable_ptr), vtable_ptr,
size_binop (MULT_EXPR,
size_int (2 * TARGET_VTABLE_DATA_ENTRY_DISTANCE),
TYPE_SIZE_UNIT (vtable_entry_type)));
TINFO_VTABLE_DECL (desc) = vtable_ptr;
}
init = tree_cons (NULL_TREE, vtable_ptr, init);
init = tree_cons (NULL_TREE, decay_conversion (name_decl), init);
init = build_constructor (NULL_TREE, nreverse (init));
TREE_CONSTANT (init) = 1;
TREE_INVARIANT (init) = 1;
TREE_STATIC (init) = 1;
init = tree_cons (NULL_TREE, init, NULL_TREE);
return init;
}
static tree
generic_initializer (tree desc, tree target)
{
tree init = tinfo_base_init (desc, target);
init = build_constructor (NULL_TREE, init);
TREE_CONSTANT (init) = 1;
TREE_INVARIANT (init) = 1;
TREE_STATIC (init) = 1;
return init;
}
static tree
ptr_initializer (tree desc, tree target)
{
tree init = tinfo_base_init (desc, target);
tree to = TREE_TYPE (target);
int flags = qualifier_flags (to);
bool incomplete = target_incomplete_p (to);
if (incomplete)
flags |= 8;
init = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, flags), init);
init = tree_cons (NULL_TREE,
get_tinfo_ptr (TYPE_MAIN_VARIANT (to)),
init);
init = build_constructor (NULL_TREE, nreverse (init));
TREE_CONSTANT (init) = 1;
TREE_INVARIANT (init) = 1;
TREE_STATIC (init) = 1;
return init;
}
static tree
ptm_initializer (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);
bool incomplete = target_incomplete_p (to);
if (incomplete)
flags |= 0x8;
if (!COMPLETE_TYPE_P (klass))
flags |= 0x10;
init = tree_cons (NULL_TREE, build_int_cst (NULL_TREE, flags), init);
init = tree_cons (NULL_TREE,
get_tinfo_ptr (TYPE_MAIN_VARIANT (to)),
init);
init = tree_cons (NULL_TREE,
get_tinfo_ptr (klass),
init);
init = build_constructor (NULL_TREE, nreverse (init));
TREE_CONSTANT (init) = 1;
TREE_INVARIANT (init) = 1;
TREE_STATIC (init) = 1;
return init;
}
static tree
class_initializer (tree desc, tree target, tree trail)
{
tree init = tinfo_base_init (desc, target);
TREE_CHAIN (init) = trail;
init = build_constructor (NULL_TREE, init);
TREE_CONSTANT (init) = 1;
TREE_INVARIANT (init) = 1;
TREE_STATIC (init) = 1;
return init;
}
static bool
typeinfo_in_lib_p (tree type)
{
if (TREE_CODE (type) == POINTER_TYPE
&& (cp_type_quals (TREE_TYPE (type)) == TYPE_QUAL_CONST
|| cp_type_quals (TREE_TYPE (type)) == TYPE_UNQUALIFIED))
type = TREE_TYPE (type);
switch (TREE_CODE (type))
{
case INTEGER_TYPE:
case BOOLEAN_TYPE:
case CHAR_TYPE:
case REAL_TYPE:
case VOID_TYPE:
return true;
default:
return false;
}
}
static tree
get_pseudo_ti_init (tree type, tree var_desc)
{
gcc_assert (at_eof);
switch (TREE_CODE (type))
{
case OFFSET_TYPE:
return ptm_initializer (var_desc, type);
case POINTER_TYPE:
return ptr_initializer (var_desc, type);
case ENUMERAL_TYPE:
return generic_initializer (var_desc, type);
break;
case FUNCTION_TYPE:
return generic_initializer (var_desc, type);
break;
case ARRAY_TYPE:
return generic_initializer (var_desc, type);
break;
case UNION_TYPE:
case RECORD_TYPE:
if (TYPE_PTRMEMFUNC_P (type))
return ptm_initializer (var_desc, type);
else if (var_desc == class_desc_type_node)
return class_initializer (var_desc, type, NULL_TREE);
else if (var_desc == si_class_desc_type_node)
{
tree base_binfo = BINFO_BASE_BINFO (TYPE_BINFO (type), 0);
tree tinfo = get_tinfo_ptr (BINFO_TYPE (base_binfo));
tree base_inits = tree_cons (NULL_TREE, tinfo, NULL_TREE);
return class_initializer (var_desc, type, base_inits);
}
else
{
int hint = ((CLASSTYPE_REPEATED_BASE_P (type) << 0)
| (CLASSTYPE_DIAMOND_SHAPED_P (type) << 1));
tree binfo = TYPE_BINFO (type);
int nbases = BINFO_N_BASE_BINFOS (binfo);
VEC (tree) *base_accesses = BINFO_BASE_ACCESSES (binfo);
tree base_inits = NULL_TREE;
int ix;
for (ix = nbases; ix--;)
{
tree base_binfo = BINFO_BASE_BINFO (binfo, ix);
tree base_init = NULL_TREE;
int flags = 0;
tree tinfo;
tree offset;
if (VEC_index (tree, base_accesses, ix) == access_public_node)
flags |= 2;
tinfo = get_tinfo_ptr (BINFO_TYPE (base_binfo));
if (BINFO_VIRTUAL_P (base_binfo))
{
offset = BINFO_VPTR_FIELD (base_binfo);
offset = convert (sizetype, offset);
flags |= 1;
}
else
offset = BINFO_OFFSET (base_binfo);
offset = cp_build_binary_op (LSHIFT_EXPR, offset,
build_int_cst (NULL_TREE, 8));
offset = cp_build_binary_op (BIT_IOR_EXPR, offset,
build_int_cst (NULL_TREE, flags));
base_init = tree_cons (NULL_TREE, offset, base_init);
base_init = tree_cons (NULL_TREE, tinfo, base_init);
base_init = build_constructor (NULL_TREE, base_init);
base_inits = tree_cons (NULL_TREE, base_init, base_inits);
}
base_inits = build_constructor (NULL_TREE, base_inits);
base_inits = tree_cons (NULL_TREE, base_inits, NULL_TREE);
base_inits = tree_cons (NULL_TREE,
build_int_cst (NULL_TREE, nbases),
base_inits);
base_inits = tree_cons (NULL_TREE,
build_int_cst (NULL_TREE, hint),
base_inits);
return class_initializer (var_desc, type, base_inits);
}
break;
default:
return generic_initializer (var_desc, type);
}
}
static tree
create_pseudo_type_info (const char *real_name, int ident, ...)
{
tree pseudo_type;
char *pseudo_name;
tree fields;
tree field_decl;
tree result;
va_list ap;
va_start (ap, ident);
pseudo_name = alloca (strlen (real_name) + 30);
strcpy (pseudo_name, real_name);
strcat (pseudo_name, "_pseudo");
if (ident)
sprintf (pseudo_name + strlen (pseudo_name), "%d", ident);
fields = build_decl (FIELD_DECL, NULL_TREE, ti_desc_type_node);
while ((field_decl = va_arg (ap, tree)))
{
TREE_CHAIN (field_decl) = fields;
fields = field_decl;
}
pseudo_type = make_aggr_type (RECORD_TYPE);
finish_builtin_struct (pseudo_type, pseudo_name, fields, NULL_TREE);
CLASSTYPE_AS_BASE (pseudo_type) = pseudo_type;
result = tree_cons (NULL_TREE, NULL_TREE, NULL_TREE);
TINFO_REAL_NAME (result) = get_identifier (real_name);
TINFO_PSEUDO_TYPE (result) =
cp_build_qualified_type (pseudo_type, TYPE_QUAL_CONST);
va_end (ap);
return result;
}
static tree
get_pseudo_ti_desc (tree type)
{
switch (TREE_CODE (type))
{
case OFFSET_TYPE:
return ptm_desc_type_node;
case POINTER_TYPE:
return ptr_desc_type_node;
case ENUMERAL_TYPE:
return enum_desc_type_node;
case FUNCTION_TYPE:
return func_desc_type_node;
case ARRAY_TYPE:
return ary_desc_type_node;
case UNION_TYPE:
case RECORD_TYPE:
if (TYPE_PTRMEMFUNC_P (type))
return ptm_desc_type_node;
else if (!COMPLETE_TYPE_P (type))
{
if (!at_eof)
cxx_incomplete_type_error (NULL_TREE, type);
return class_desc_type_node;
}
else if (!BINFO_N_BASE_BINFOS (TYPE_BINFO (type)))
return class_desc_type_node;
else
{
tree binfo = TYPE_BINFO (type);
VEC (tree) *base_accesses = BINFO_BASE_ACCESSES (binfo);
tree base_binfo = BINFO_BASE_BINFO (binfo, 0);
int num_bases = BINFO_N_BASE_BINFOS (binfo);
if (num_bases == 1
&& VEC_index (tree, base_accesses, 0) == access_public_node
&& !BINFO_VIRTUAL_P (base_binfo)
&& integer_zerop (BINFO_OFFSET (base_binfo)))
return si_class_desc_type_node;
else
{
tree var_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;
}
var_desc = TREE_VEC_ELT (vmi_class_desc_type_node, num_bases);
if (var_desc)
return var_desc;
if (abi_version_at_least (2))
array_domain = build_index_type (size_int (num_bases - 1));
else
array_domain = build_index_type (size_int (num_bases));
base_array =
build_array_type (base_desc_type_node, array_domain);
push_nested_namespace (abi_node);
var_desc = create_pseudo_type_info
("__vmi_class_type_info", num_bases,
build_decl (FIELD_DECL, NULL_TREE, integer_type_node),
build_decl (FIELD_DECL, NULL_TREE, integer_type_node),
build_decl (FIELD_DECL, NULL_TREE, base_array),
NULL);
pop_nested_namespace (abi_node);
TREE_VEC_ELT (vmi_class_desc_type_node, num_bases) = var_desc;
return var_desc;
}
}
default:
return bltn_desc_type_node;
}
}
static void
create_tinfo_types (void)
{
gcc_assert (!ti_desc_type_node);
push_nested_namespace (abi_node);
{
tree field, fields;
ti_desc_type_node = make_aggr_type (RECORD_TYPE);
field = build_decl (FIELD_DECL, NULL_TREE, const_ptr_type_node);
fields = field;
field = build_decl (FIELD_DECL, NULL_TREE, const_string_type_node);
TREE_CHAIN (field) = fields;
fields = field;
finish_builtin_struct (ti_desc_type_node, "__type_info_pseudo",
fields, NULL_TREE);
TYPE_HAS_CONSTRUCTOR (ti_desc_type_node) = 1;
}
bltn_desc_type_node = create_pseudo_type_info
("__fundamental_type_info", 0,
NULL);
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_desc_type_node = create_pseudo_type_info
("__class_type_info", 0,
NULL);
si_class_desc_type_node = create_pseudo_type_info
("__si_class_type_info", 0,
build_decl (FIELD_DECL, NULL_TREE, type_info_ptr_type),
NULL);
{
tree field, fields;
field = build_decl (FIELD_DECL, NULL_TREE, type_info_ptr_type);
fields = field;
field = build_decl (FIELD_DECL, NULL_TREE, integer_types[itk_long]);
TREE_CHAIN (field) = fields;
fields = field;
base_desc_type_node = make_aggr_type (RECORD_TYPE);
finish_builtin_struct (base_desc_type_node, "__base_class_type_info_pseudo",
fields, NULL_TREE);
TYPE_HAS_CONSTRUCTOR (base_desc_type_node) = 1;
}
vmi_class_desc_type_node = make_tree_vec (10);
ptr_desc_type_node = create_pseudo_type_info
("__pointer_type_info", 0,
build_decl (FIELD_DECL, NULL_TREE, integer_type_node),
build_decl (FIELD_DECL, NULL_TREE, type_info_ptr_type),
NULL);
ptm_desc_type_node = create_pseudo_type_info
("__pointer_to_member_type_info", 0,
build_decl (FIELD_DECL, NULL_TREE, integer_type_node),
build_decl (FIELD_DECL, NULL_TREE, type_info_ptr_type),
build_decl (FIELD_DECL, NULL_TREE, type_info_ptr_type),
NULL);
pop_nested_namespace (abi_node);
}
void
emit_support_tinfos (void)
{
static tree *const fundamentals[] =
{
&void_type_node,
&boolean_type_node,
&wchar_type_node,
&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,
0
};
int ix;
tree bltn_type, dtor;
push_nested_namespace (abi_node);
bltn_type = xref_tag (class_type,
get_identifier ("__fundamental_type_info"),
ts_global, false);
pop_nested_namespace (abi_node);
if (!COMPLETE_TYPE_P (bltn_type))
return;
dtor = CLASSTYPE_DESTRUCTORS (bltn_type);
if (!dtor || DECL_EXTERNAL (dtor))
return;
doing_runtime = 1;
for (ix = 0; fundamentals[ix]; ix++)
{
tree bltn = *fundamentals[ix];
tree types[3];
int i;
types[0] = bltn;
types[1] = build_pointer_type (bltn);
types[2] = build_pointer_type (build_qualified_type (bltn,
TYPE_QUAL_CONST));
for (i = 0; i < 3; ++i)
{
tree tinfo;
tinfo = get_tinfo_decl (types[i]);
TREE_USED (tinfo) = 1;
mark_needed (tinfo);
if (!flag_weak)
{
gcc_assert (TREE_PUBLIC (tinfo) && !DECL_COMDAT (tinfo));
DECL_INTERFACE_KNOWN (tinfo) = 1;
}
}
}
}
bool
emit_tinfo_decl (tree decl)
{
tree type = TREE_TYPE (DECL_NAME (decl));
int in_library = typeinfo_in_lib_p (type);
tree var_desc, var_init;
gcc_assert (DECL_TINFO_P (decl));
if (in_library)
{
if (doing_runtime)
DECL_EXTERNAL (decl) = 0;
else
{
DECL_INTERFACE_KNOWN (decl) = 1;
return false;
}
}
else if (involves_incomplete_p (type))
{
if (!decl_needed_p (decl))
return false;
TREE_PUBLIC (decl) = 0;
DECL_EXTERNAL (decl) = 0;
DECL_INTERFACE_KNOWN (decl) = 1;
}
import_export_decl (decl);
if (DECL_NOT_REALLY_EXTERN (decl) && decl_needed_p (decl))
{
DECL_EXTERNAL (decl) = 0;
var_desc = get_pseudo_ti_desc (type);
var_init = get_pseudo_ti_init (type, var_desc);
DECL_INITIAL (decl) = var_init;
mark_used (decl);
cp_finish_decl (decl, var_init, NULL_TREE, 0);
return true;
}
else
return false;
}