#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"
#include "target.h"
typedef struct tinfo_s GTY (())
{
tree type;
tree vtable;
tree name;
} tinfo_s;
DEF_VEC_O(tinfo_s);
DEF_VEC_ALLOC_O(tinfo_s,gc);
typedef enum tinfo_kind
{
TK_TYPE_INFO_TYPE,
TK_BASE_TYPE,
TK_BUILTIN_TYPE,
TK_ARRAY_TYPE,
TK_FUNCTION_TYPE,
TK_ENUMERAL_TYPE,
TK_POINTER_TYPE,
TK_POINTER_MEMBER_TYPE,
TK_CLASS_TYPE,
TK_SI_CLASS_TYPE,
TK_FIXED
} tinfo_kind;
VEC(tree,gc) *unemitted_tinfo_decls;
static GTY (()) VEC(tinfo_s,gc) *tinfo_descs;
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 (tinfo_s *, tree);
static tree generic_initializer (tinfo_s *, tree);
static tree ptr_initializer (tinfo_s *, tree);
static tree ptm_initializer (tinfo_s *, tree);
static tree class_initializer (tinfo_s *, tree, tree);
static void create_pseudo_type_info (int, const char *, ...);
static tree get_pseudo_ti_init (tree, unsigned);
static unsigned get_pseudo_ti_index (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_current, 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, gc, 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 (error_operand_p (exp))
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 (variably_modified_type_p (type, NULL_TREE))
{
error ("cannot create type information for type %qT because "
"it involves types of variable size",
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)
{
int ix = get_pseudo_ti_index (type);
tinfo_s *ti = VEC_index (tinfo_s, tinfo_descs, ix);
d = build_lang_decl (VAR_DECL, name, ti->type);
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, gc, 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,
cp_convert (TREE_TYPE (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;
used_types_insert (type);
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);
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;
}
expr = convert_to_reference (exprtype, expr, CONV_IMPLICIT,
LOOKUP_NORMAL, NULL_TREE);
}
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 = rvalue (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 (0, "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 (0, "dynamic_cast of %q#D to %q#T can never succeed",
op, type);
retval = build_int_cst (type, 0);
return retval;
}
}
if (!flag_rtti)
{
error ("%<dynamic_cast%> not permitted with -fno-rtti");
return error_mark_node;
}
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_current, 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 ();
tree neq;
result = save_expr (result);
neq = c_common_truthvalue_conversion (result);
return build3 (COND_EXPR, type, neq, 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 (tinfo_s *ti, 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;
set_linkage_according_to_type (target, name_decl);
if (doing_runtime && ! targetm.cxx.library_rtti_comdat ())
DECL_INTERFACE_KNOWN (name_decl) = 1;
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 = ti->vtable;
if (!vtable_ptr)
{
tree real_type;
push_nested_namespace (abi_node);
real_type = xref_tag (class_type, ti->name,
ts_current, 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)));
ti->vtable = vtable_ptr;
}
init = tree_cons (NULL_TREE, vtable_ptr, init);
init = tree_cons (NULL_TREE, decay_conversion (name_decl), init);
init = build_constructor_from_list (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 (tinfo_s *ti, tree target)
{
tree init = tinfo_base_init (ti, target);
init = build_constructor_from_list (NULL_TREE, init);
TREE_CONSTANT (init) = 1;
TREE_INVARIANT (init) = 1;
TREE_STATIC (init) = 1;
return init;
}
static tree
ptr_initializer (tinfo_s *ti, tree target)
{
tree init = tinfo_base_init (ti, 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_from_list (NULL_TREE, nreverse (init));
TREE_CONSTANT (init) = 1;
TREE_INVARIANT (init) = 1;
TREE_STATIC (init) = 1;
return init;
}
static tree
ptm_initializer (tinfo_s *ti, tree target)
{
tree init = tinfo_base_init (ti, 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_from_list (NULL_TREE, nreverse (init));
TREE_CONSTANT (init) = 1;
TREE_INVARIANT (init) = 1;
TREE_STATIC (init) = 1;
return init;
}
static tree
class_initializer (tinfo_s *ti, tree target, tree trail)
{
tree init = tinfo_base_init (ti, target);
TREE_CHAIN (init) = trail;
init = build_constructor_from_list (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 REAL_TYPE:
case VOID_TYPE:
return true;
default:
return false;
}
}
static tree
get_pseudo_ti_init (tree type, unsigned tk_index)
{
tinfo_s *ti = VEC_index (tinfo_s, tinfo_descs, tk_index);
gcc_assert (at_eof);
switch (tk_index)
{
case TK_POINTER_MEMBER_TYPE:
return ptm_initializer (ti, type);
case TK_POINTER_TYPE:
return ptr_initializer (ti, type);
case TK_BUILTIN_TYPE:
case TK_ENUMERAL_TYPE:
case TK_FUNCTION_TYPE:
case TK_ARRAY_TYPE:
return generic_initializer (ti, type);
case TK_CLASS_TYPE:
return class_initializer (ti, type, NULL_TREE);
case TK_SI_CLASS_TYPE:
{
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);
ti = VEC_index (tinfo_s, tinfo_descs, tk_index);
return class_initializer (ti, type, base_inits);
}
default:
{
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,gc) *base_accesses = BINFO_BASE_ACCESSES (binfo);
tree base_inits = NULL_TREE;
int ix;
gcc_assert (tk_index >= TK_FIXED);
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_from_list (NULL_TREE, base_init);
base_inits = tree_cons (NULL_TREE, base_init, base_inits);
}
base_inits = build_constructor_from_list (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);
ti = VEC_index (tinfo_s, tinfo_descs, tk_index);
return class_initializer (ti, type, base_inits);
}
}
}
static void
create_pseudo_type_info (int tk, const char *real_name, ...)
{
tinfo_s *ti;
tree pseudo_type;
char *pseudo_name;
tree fields;
tree field_decl;
va_list ap;
va_start (ap, real_name);
pseudo_name = (char *) alloca (strlen (real_name) + 30);
strcpy (pseudo_name, real_name);
strcat (pseudo_name, "_pseudo");
if (tk >= TK_FIXED)
sprintf (pseudo_name + strlen (pseudo_name), "%d", tk - TK_FIXED);
fields = build_decl (FIELD_DECL, NULL_TREE,
VEC_index (tinfo_s, tinfo_descs,
TK_TYPE_INFO_TYPE)->type);
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;
ti = VEC_index (tinfo_s, tinfo_descs, tk);
ti->type = cp_build_qualified_type (pseudo_type, TYPE_QUAL_CONST);
ti->name = get_identifier (real_name);
ti->vtable = NULL_TREE;
TREE_PUBLIC (TYPE_MAIN_DECL (ti->type)) = 1;
va_end (ap);
}
static unsigned
get_pseudo_ti_index (tree type)
{
unsigned ix;
switch (TREE_CODE (type))
{
case OFFSET_TYPE:
ix = TK_POINTER_MEMBER_TYPE;
break;
case POINTER_TYPE:
ix = TK_POINTER_TYPE;
break;
case ENUMERAL_TYPE:
ix = TK_ENUMERAL_TYPE;
break;
case FUNCTION_TYPE:
ix = TK_FUNCTION_TYPE;
break;
case ARRAY_TYPE:
ix = TK_ARRAY_TYPE;
break;
case UNION_TYPE:
case RECORD_TYPE:
if (TYPE_PTRMEMFUNC_P (type))
{
ix = TK_POINTER_MEMBER_TYPE;
break;
}
else if (!COMPLETE_TYPE_P (type))
{
if (!at_eof)
cxx_incomplete_type_error (NULL_TREE, type);
ix = TK_CLASS_TYPE;
break;
}
else if (!BINFO_N_BASE_BINFOS (TYPE_BINFO (type)))
{
ix = TK_CLASS_TYPE;
break;
}
else
{
tree binfo = TYPE_BINFO (type);
VEC(tree,gc) *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)))
{
ix = TK_SI_CLASS_TYPE;
break;
}
else
{
tinfo_s *ti;
tree array_domain, base_array;
ix = TK_FIXED + num_bases;
if (VEC_length (tinfo_s, tinfo_descs) <= ix)
{
unsigned len = VEC_length (tinfo_s, tinfo_descs);
VEC_safe_grow (tinfo_s, gc, tinfo_descs, ix + 1);
while (VEC_iterate (tinfo_s, tinfo_descs, len++, ti))
ti->type = ti->vtable = ti->name = NULL_TREE;
}
else if (VEC_index (tinfo_s, tinfo_descs, ix)->type)
break;
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 (VEC_index (tinfo_s, tinfo_descs,
TK_BASE_TYPE)->type,
array_domain);
push_nested_namespace (abi_node);
create_pseudo_type_info
(ix, "__vmi_class_type_info",
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);
break;
}
}
default:
ix = TK_BUILTIN_TYPE;
break;
}
return ix;
}
static void
create_tinfo_types (void)
{
tinfo_s *ti;
gcc_assert (!tinfo_descs);
VEC_safe_grow (tinfo_s, gc, tinfo_descs, TK_FIXED);
push_nested_namespace (abi_node);
{
tree field, fields;
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;
ti = VEC_index (tinfo_s, tinfo_descs, TK_TYPE_INFO_TYPE);
ti->type = make_aggr_type (RECORD_TYPE);
ti->vtable = NULL_TREE;
ti->name = NULL_TREE;
finish_builtin_struct (ti->type, "__type_info_pseudo",
fields, NULL_TREE);
TYPE_HAS_CONSTRUCTOR (ti->type) = 1;
}
create_pseudo_type_info (TK_BUILTIN_TYPE, "__fundamental_type_info", NULL);
create_pseudo_type_info (TK_ARRAY_TYPE, "__array_type_info", NULL);
create_pseudo_type_info (TK_FUNCTION_TYPE, "__function_type_info", NULL);
create_pseudo_type_info (TK_ENUMERAL_TYPE, "__enum_type_info", NULL);
create_pseudo_type_info (TK_CLASS_TYPE, "__class_type_info", NULL);
create_pseudo_type_info (TK_SI_CLASS_TYPE, "__si_class_type_info",
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;
ti = VEC_index (tinfo_s, tinfo_descs, TK_BASE_TYPE);
ti->type = make_aggr_type (RECORD_TYPE);
ti->vtable = NULL_TREE;
ti->name = NULL_TREE;
finish_builtin_struct (ti->type, "__base_class_type_info_pseudo",
fields, NULL_TREE);
TYPE_HAS_CONSTRUCTOR (ti->type) = 1;
}
create_pseudo_type_info (TK_POINTER_TYPE, "__pointer_type_info",
build_decl (FIELD_DECL, NULL_TREE, integer_type_node),
build_decl (FIELD_DECL, NULL_TREE, type_info_ptr_type),
NULL);
create_pseudo_type_info (TK_POINTER_MEMBER_TYPE,
"__pointer_to_member_type_info",
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_current, 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 || ! targetm.cxx.library_rtti_comdat ())
{
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);
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))
{
tree init;
DECL_EXTERNAL (decl) = 0;
init = get_pseudo_ti_init (type, get_pseudo_ti_index (type));
DECL_INITIAL (decl) = init;
mark_used (decl);
finish_decl (decl, init, NULL_TREE);
return true;
}
else
return false;
}
#include "gt-cp-rtti.h"