/* RunTime Type Identification
Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Mostly written by Jason Merrill (jason@cygnus.com).
This file is part of GNU CC.
extern tree build_t_desc_overload ();
extern struct obstack *permanent_obstack;
+tree type_info_type_node;
+tree tinfo_fn_id;
+tree tinfo_fn_type;
+
/* in c-common.c */
extern tree combine_strings PROTO((tree));
\f
-/* Given the expression EXP of type `class *', return the head
- of the object pointed to by EXP. */
+void
+init_rtti_processing ()
+{
+ type_info_type_node = xref_tag
+ (class_type_node, get_identifier ("type_info"), NULL_TREE, 1);
+ tinfo_fn_id = get_identifier ("__tf");
+ tinfo_fn_type = build_function_type
+ (build_reference_type (build_type_variant (type_info_type_node, 1, 0)),
+ void_list_node);
+}
+
+/* Given a pointer to an object with at least one virtual table
+ pointer somewhere, return a pointer to a possible sub-object that
+ has a virtual table pointer in it that is the vtable parent for
+ that sub-object. */
+static tree
+build_headof_sub (exp)
+ tree exp;
+{
+ tree type = TREE_TYPE (TREE_TYPE (exp));
+ tree basetype = CLASSTYPE_RTTI (type);
+ tree binfo = get_binfo (basetype, type, 0);
+
+ exp = convert_pointer_to_real (binfo, exp);
+ return exp;
+}
+
+/* Given the expression EXP of type `class *', return the head of the
+ object pointed to by EXP with type cv void*, if the class has any
+ virtual functions (TYPE_VIRTUAL_P), else just return the
+ expression. */
static tree
build_headof (exp)
tree exp;
{
tree type = TREE_TYPE (exp);
+ tree aref;
tree vptr, offset;
if (TREE_CODE (type) != POINTER_TYPE)
}
type = TREE_TYPE (type);
- if (!TYPE_VIRTUAL_P (type) || CLASSTYPE_VFIELD (type) == NULL_TREE)
+ if (!TYPE_VIRTUAL_P (type))
return exp;
- vptr = fold (size_binop (PLUS_EXPR,
- size_binop (FLOOR_DIV_EXPR,
- DECL_FIELD_BITPOS (CLASSTYPE_VFIELD (type)),
- size_int (BITS_PER_UNIT)),
- exp));
- vptr = build1 (INDIRECT_REF, build_pointer_type (vtable_entry_type), vptr);
+ /* If we don't have rtti stuff, get to a sub-object that does. */
+ if (!CLASSTYPE_VFIELDS (TREE_TYPE (TREE_TYPE (exp))))
+ exp = build_headof_sub (exp);
+
+ /* We use this a couple of times below, protect it. */
+ exp = save_expr (exp);
+
+ aref = build_vtbl_ref (build_indirect_ref (exp, NULL_PTR), integer_zero_node);
if (flag_vtable_thunks)
- offset = build_array_ref (vptr, integer_zero_node);
+ offset = aref;
else
- offset = build_component_ref (build_array_ref (vptr, integer_zero_node),
- delta_identifier,
- NULL_TREE, 0);
+ offset = build_component_ref (aref, delta_identifier, NULL_TREE, 0);
type = build_type_variant (ptr_type_node, TREE_READONLY (exp),
TREE_THIS_VOLATILE (exp));
{
tree type;
- if (!flag_rtti)
- cp_error ("cannot take typeid of object when -frtti is not specified");
-
if (exp == error_mark_node)
return error_mark_node;
/* build reference to type_info from vtable. */
tree t;
+ if (! flag_rtti)
+ warning ("taking dynamic typeid of object without -frtti");
+
+ /* If we don't have rtti stuff, get to a sub-object that does. */
+ if (!CLASSTYPE_VFIELDS (TREE_TYPE (type)))
+ {
+ exp = build_unary_op (ADDR_EXPR, exp, 0);
+ exp = build_headof_sub (exp);
+ exp = build_indirect_ref (exp, NULL_PTR);
+ }
+
if (flag_vtable_thunks)
- t = build_vfn_ref ((tree *) NULL_TREE, exp, integer_one_node);
+ t = build_vfn_ref ((tree *) 0, exp, integer_one_node);
else
- t = build_vfn_ref ((tree *) NULL_TREE, exp, integer_zero_node);
+ t = build_vfn_ref ((tree *) 0, exp, integer_zero_node);
+ TREE_TYPE (t) = build_pointer_type (tinfo_fn_type);
- TREE_TYPE (t) = build_pointer_type (__class_desc_type_node);
- t = build_indirect_ref (t, NULL);
- return t;
+ t = build (CALL_EXPR, TREE_TYPE (tinfo_fn_type), t, NULL_TREE, 0);
+ TREE_SIDE_EFFECTS (t) = 1;
+ return convert_from_reference (t);
}
/* otherwise return the type_info for the static type of the expr. */
return get_typeid (type);
}
+tree
+get_tinfo_var (type)
+ tree type;
+{
+ tree tname = build_overload_with_type (get_identifier ("__ti"), type);
+ tree tdecl, arrtype;
+ int size;
+
+ if (IDENTIFIER_GLOBAL_VALUE (tname))
+ return IDENTIFIER_GLOBAL_VALUE (tname);
+
+ /* Figure out how much space we need to allocate for the type_info object.
+ If our struct layout or the type_info classes are changed, this will
+ need to be modified. */
+ if (TYPE_VOLATILE (type) || TYPE_READONLY (type))
+ size = 4 * POINTER_SIZE;
+ else if (TREE_CODE (type) == POINTER_TYPE
+ && ! (TREE_CODE (TREE_TYPE (type)) == OFFSET_TYPE
+ || TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE))
+ size = 3 * POINTER_SIZE;
+ else if (IS_AGGR_TYPE (type))
+ {
+ if (CLASSTYPE_N_BASECLASSES (type) == 0)
+ size = 2 * POINTER_SIZE;
+ else if (! TYPE_USES_COMPLEX_INHERITANCE (type)
+ && (TREE_VIA_PUBLIC
+ (TREE_VEC_ELT (TYPE_BINFO_BASETYPES (type), 0))))
+ size = 3 * POINTER_SIZE;
+ else
+ size = 4 * POINTER_SIZE;
+ }
+ else
+ size = 2 * POINTER_SIZE;
+
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+
+ /* The type for a character array of the appropriate size. */
+ arrtype = build_cplus_array_type
+ (unsigned_char_type_node,
+ build_index_type (size_int (size / BITS_PER_UNIT - 1)));
+
+ tdecl = build_decl (VAR_DECL, tname, arrtype);
+ TREE_PUBLIC (tdecl) = 1;
+ DECL_EXTERNAL (tdecl) = 1;
+ DECL_ARTIFICIAL (tdecl) = 1;
+ pushdecl_top_level (tdecl);
+ cp_finish_decl (tdecl, NULL_TREE, NULL_TREE, 0, 0);
+
+ pop_obstacks ();
+
+ return tdecl;
+}
+
+tree
+get_tinfo_fn (type)
+ tree type;
+{
+ tree name = build_overload_with_type (tinfo_fn_id, type);
+ tree d;
+
+ if (IDENTIFIER_GLOBAL_VALUE (name))
+ return IDENTIFIER_GLOBAL_VALUE (name);
+
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+
+ d = build_lang_decl (FUNCTION_DECL, name, tinfo_fn_type);
+ DECL_EXTERNAL (d) = 1;
+ TREE_PUBLIC (d) = 1;
+ DECL_ARTIFICIAL (d) = 1;
+ DECL_NOT_REALLY_EXTERN (d) = 1;
+ DECL_MUTABLE_P (d) = 1;
+ TREE_TYPE (name) = type;
+ pushdecl_top_level (d);
+ make_function_rtl (d);
+ mark_inline_for_output (d);
+ if (at_eof)
+ import_export_decl (d);
+
+ pop_obstacks ();
+
+ return d;
+}
+
+tree
+get_typeid_1 (type)
+ tree type;
+{
+ tree t = build (CALL_EXPR, TREE_TYPE (tinfo_fn_type),
+ default_conversion (get_tinfo_fn (type)), NULL_TREE, 0);
+ TREE_SIDE_EFFECTS (t) = 1;
+ return convert_from_reference (t);
+}
+
/* Return the type_info object for TYPE, creating it if necessary. */
tree
get_typeid (type)
tree type;
{
- tree t, td;
+ tree t;
if (type == error_mark_node)
return error_mark_node;
- /* Is it useful (and/or correct) to have different typeids for `T &'
- and `T'? */
+ /* If the type of the type-id is a reference type, the result of the
+ typeid expression refers to a type_info object representing the
+ referenced type. */
if (TREE_CODE (type) == REFERENCE_TYPE)
type = TREE_TYPE (type);
- td = build_t_desc (type, 1);
- if (td == error_mark_node)
- return error_mark_node;
+ /* The top-level cv-qualifiers of the lvalue expression or the type-id
+ that is the operand of typeid are always ignored. */
+ type = TYPE_MAIN_VARIANT (type);
- t = TREE_OPERAND (td, 0);
- return t;
+ return get_typeid_1 (type);
}
/* Get a bad_cast node for the program to throw...
- See libstdc++::exception{,.cc} for __bad_cast_object */
+ See libstdc++/exception.cc for __throw_bad_cast */
+
static tree
-get_bad_cast_node ()
+throw_bad_cast ()
{
- static tree t;
- if (t == NULL_TREE
- && (t = lookup_name (get_identifier ("__bad_cast_object"), 0))
- == NULL_TREE)
- {
- error ("you must #include <typeinfo>");
- return error_mark_node;
- }
- return t;
+ tree d = get_identifier ("__throw_bad_cast");
+ tree type;
+
+ if (IDENTIFIER_GLOBAL_VALUE (d))
+ return IDENTIFIER_GLOBAL_VALUE (d);
+
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+
+ type = build_function_type (void_type_node, void_list_node);
+ d = build_lang_decl (FUNCTION_DECL, d, type);
+ DECL_EXTERNAL (d) = 1;
+ TREE_PUBLIC (d) = 1;
+ DECL_ARTIFICIAL (d) = 1;
+ pushdecl_top_level (d);
+ make_function_rtl (d);
+
+ pop_obstacks ();
+
+ d = build (CALL_EXPR, void_type_node, default_conversion (d), NULL_TREE, 0);
+ TREE_SIDE_EFFECTS (d) = 1;
+ return d;
}
/* Execute a dynamic cast, as described in section 5.2.6 of the 9/93 working
paper. */
+
tree
build_dynamic_cast (type, expr)
tree type, expr;
enum tree_code tc = TREE_CODE (type);
tree exprtype = TREE_TYPE (expr);
enum tree_code ec = TREE_CODE (exprtype);
+ tree dcast_fn;
if (type == error_mark_node || expr == error_mark_node)
return error_mark_node;
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == RECORD_TYPE)
return build1 (NOP_EXPR, type, expr);
- return build_headof (expr);
+ expr = build_headof (expr);
+ if (TREE_TYPE (expr) != type)
+ expr = build1 (NOP_EXPR, type, expr);
+ return expr;
}
else
{
tree retval;
- tree result, td1, td2, elems, expr1;
+ tree result, td1, td2, td3, elems, expr1, expr2;
/* If we got here, we can't convert statically. Therefore,
dynamic_cast<D&>(b) (b an object) cannot succeed. */
{
cp_warning ("dynamic_cast of `%#D' to `%#T' can never succeed",
expr, type);
- return build_throw (get_bad_cast_node ());
+ return throw_bad_cast ();
}
}
/* Ditto for dynamic_cast<D*>(&b). */
}
}
+ /* 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. */
- expr1 = build_headof (expr1);
+ expr2 = build_headof (expr1);
if (ec == POINTER_TYPE)
td1 = build_typeid (build_indirect_ref (expr, NULL_PTR));
else
td1 = build_typeid (expr);
- td2 = get_typeid (TYPE_MAIN_VARIANT (TREE_TYPE (type)));
-
- elems = tree_cons (NULL_TREE, td2,
- tree_cons (NULL_TREE, build_int_2 (1, 0),
- tree_cons (NULL_TREE, expr1, NULL_TREE)));
- result = build_method_call (td1,
- get_identifier ("__rtti_match"), elems, NULL_TREE, LOOKUP_NORMAL);
+ td2 = get_typeid (TREE_TYPE (type));
+ td3 = get_typeid (TREE_TYPE (exprtype));
+
+ elems = tree_cons
+ (NULL_TREE, TREE_OPERAND (td1, 0), tree_cons
+ (NULL_TREE, TREE_OPERAND (td2, 0), tree_cons
+ (NULL_TREE, build_int_2 (1, 0), tree_cons
+ (NULL_TREE, expr2, tree_cons
+ (NULL_TREE, TREE_OPERAND (td3, 0), tree_cons
+ (NULL_TREE, expr1, NULL_TREE))))));
+
+ dcast_fn = get_identifier ("__dynamic_cast");
+ if (IDENTIFIER_GLOBAL_VALUE (dcast_fn))
+ dcast_fn = IDENTIFIER_GLOBAL_VALUE (dcast_fn);
+ else
+ {
+ tree tmp;
+
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+ tmp = build_reference_type
+ (build_type_variant (type_info_type_node, 1, 0));
+ tmp = tree_cons
+ (NULL_TREE, tmp, tree_cons
+ (NULL_TREE, tmp, tree_cons
+ (NULL_TREE, integer_type_node, tree_cons
+ (NULL_TREE, ptr_type_node, tree_cons
+ (NULL_TREE, tmp, tree_cons
+ (NULL_TREE, ptr_type_node, void_list_node))))));
+ tmp = build_function_type (ptr_type_node, tmp);
+ dcast_fn = build_lang_decl (FUNCTION_DECL, dcast_fn, tmp);
+ DECL_EXTERNAL (dcast_fn) = 1;
+ TREE_PUBLIC (dcast_fn) = 1;
+ DECL_ARTIFICIAL (dcast_fn) = 1;
+ pushdecl_top_level (dcast_fn);
+ make_function_rtl (dcast_fn);
+ pop_obstacks ();
+ }
+
+ result = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (dcast_fn)),
+ decay_conversion (dcast_fn), elems, 0);
+ TREE_SIDE_EFFECTS (result) = 1;
if (tc == REFERENCE_TYPE)
{
- expr1 = build_throw (get_bad_cast_node ());
+ expr1 = throw_bad_cast ();
expr1 = build_compound_expr (tree_cons (NULL_TREE, expr1,
build_tree_list (NULL_TREE, convert (type, integer_zero_node))));
TREE_TYPE (expr1) = type;
Note: these constructors always return the address of the descriptor
info, since that is simplest for their mutual interaction. */
-static tree
-build_generic_desc (tdecl, type, elems)
- tree tdecl;
- tree type;
- tree elems;
-{
- tree init = elems;
- int toplev = global_bindings_p ();
+extern tree const_string_type_node;
- TREE_CONSTANT (init) = 1;
- TREE_STATIC (init) = 1;
- TREE_READONLY (init) = 1;
+/* Build an initializer for a __si_type_info node. */
- TREE_TYPE (tdecl) = type;
- DECL_INITIAL (tdecl) = init;
- TREE_STATIC (tdecl) = 1;
- DECL_SIZE (tdecl) = NULL_TREE;
- layout_decl (tdecl, 0);
- if (! toplev)
- push_to_top_level ();
- cp_finish_decl (tdecl, init, NULL_TREE, 0, 0);
- if (! toplev)
- pop_from_top_level ();
-
- if (! TREE_USED (tdecl))
- {
- assemble_external (tdecl);
- TREE_USED (tdecl) = 1;
- }
-
- return IDENTIFIER_AS_DESC (DECL_NAME (tdecl));
-}
-
-/* Build an initializer for a __bltn_desc node. */
-static tree
-build_bltn_desc (tdecl, type)
+static void
+expand_si_desc (tdecl, type)
tree tdecl;
tree type;
{
- tree elems, t;
-
- if (type == boolean_type_node)
- t = lookup_field (__bltn_desc_type_node, get_identifier("_RTTI_BI_BOOL"),
- 0, 0);
- else if (type == char_type_node)
- t = lookup_field (__bltn_desc_type_node, get_identifier("_RTTI_BI_CHAR"),
- 0, 0);
- else if (type == short_integer_type_node)
- t = lookup_field (__bltn_desc_type_node, get_identifier("_RTTI_BI_SHORT"),
- 0, 0);
- else if (type == integer_type_node)
- t = lookup_field (__bltn_desc_type_node, get_identifier("_RTTI_BI_INT"),
- 0, 0);
- else if (type == long_integer_type_node)
- t = lookup_field (__bltn_desc_type_node, get_identifier("_RTTI_BI_LONG"),
- 0, 0);
- else if (type == long_long_integer_type_node)
- t = lookup_field (__bltn_desc_type_node,
- get_identifier("_RTTI_BI_LONGLONG"), 0, 0);
- else if (type == float_type_node)
- t = lookup_field (__bltn_desc_type_node, get_identifier("_RTTI_BI_FLOAT"),
- 0, 0);
- else if (type == double_type_node)
- t = lookup_field (__bltn_desc_type_node,
- get_identifier("_RTTI_BI_DOUBLE"), 0, 0);
- else if (type == long_double_type_node)
- t = lookup_field (__bltn_desc_type_node,
- get_identifier("_RTTI_BI_LDOUBLE"), 0, 0);
- else if (type == unsigned_char_type_node)
- t = lookup_field (__bltn_desc_type_node, get_identifier("_RTTI_BI_UCHAR"),
- 0, 0);
- else if (type == short_unsigned_type_node)
- t = lookup_field (__bltn_desc_type_node, get_identifier("_RTTI_BI_USHORT"),
- 0, 0);
- else if (type == unsigned_type_node)
- t = lookup_field (__bltn_desc_type_node, get_identifier("_RTTI_BI_UINT"),
- 0, 0);
- else if (type == long_unsigned_type_node)
- t = lookup_field (__bltn_desc_type_node, get_identifier("_RTTI_BI_ULONG"),
- 0, 0);
- else if (type == long_long_unsigned_type_node)
- t = lookup_field (__bltn_desc_type_node,
- get_identifier("_RTTI_BI_ULONGLONG"), 0, 0);
- else if (type == signed_char_type_node)
- t = lookup_field (__bltn_desc_type_node, get_identifier("_RTTI_BI_SCHAR"),
- 0, 0);
- else if (type == wchar_type_node)
- t = lookup_field (__bltn_desc_type_node, get_identifier("_RTTI_BI_WCHAR"),
- 0, 0);
- else if (type == void_type_node)
- t = lookup_field (__bltn_desc_type_node, get_identifier("_RTTI_BI_VOID"),
- 0, 0);
+ tree t, elems, fn;
+ char *name = build_overload_name (type, 1, 1);
+ tree name_string = combine_strings (build_string (strlen (name), name));
+
+ type = BINFO_TYPE (TREE_VEC_ELT (TYPE_BINFO_BASETYPES (type), 0));
+ expand_expr_stmt (get_typeid_1 (type));
+ t = decay_conversion (get_tinfo_var (type));
+ elems = tree_cons
+ (NULL_TREE, decay_conversion (tdecl), tree_cons
+ (NULL_TREE, decay_conversion (name_string), tree_cons
+ (NULL_TREE, t, NULL_TREE)));
+
+ fn = get_identifier ("__rtti_si");
+ if (IDENTIFIER_GLOBAL_VALUE (fn))
+ fn = IDENTIFIER_GLOBAL_VALUE (fn);
else
{
- cp_compiler_error ("type `%T' not handled as a built-in type");
+ tree tmp;
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+ tmp = tree_cons
+ (NULL_TREE, ptr_type_node, tree_cons
+ (NULL_TREE, const_string_type_node, tree_cons
+ (NULL_TREE, build_pointer_type (type_info_type_node),
+ void_list_node)));
+ tmp = build_function_type (void_type_node, tmp);
+
+ fn = build_lang_decl (FUNCTION_DECL, fn, tmp);
+ DECL_EXTERNAL (fn) = 1;
+ TREE_PUBLIC (fn) = 1;
+ DECL_ARTIFICIAL (fn) = 1;
+ pushdecl_top_level (fn);
+ make_function_rtl (fn);
+ pop_obstacks ();
}
- elems = tree_cons (NULL_TREE, t, NULL_TREE);
- return build_generic_desc (tdecl, __bltn_desc_type_node, elems);
-}
-
-/* Build an initializer for a __user_desc node. */
-static tree
-build_user_desc (tdecl)
- tree tdecl;
-{
- tree elems, name_string;
- tree tname = DECL_NAME (tdecl);
-
- name_string = combine_strings (build_string
- (IDENTIFIER_LENGTH (tname)+1, IDENTIFIER_POINTER (tname)));
- elems = name_string;
- return build_generic_desc (tdecl, __user_desc_type_node, elems);
+ fn = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
+ decay_conversion (fn), elems, 0);
+ TREE_SIDE_EFFECTS (fn) = 1;
+ expand_expr_stmt (fn);
}
/* Build an initializer for a __class_type_info node. */
-static tree
-build_class_desc (tdecl, type)
+
+static void
+expand_class_desc (tdecl, type)
tree tdecl;
tree type;
{
- tree tname = DECL_NAME (tdecl);
+ tree tname = TYPE_NESTED_NAME (type);
tree name_string;
+ tree fn, tmp;
+ char *name;
int i = CLASSTYPE_N_BASECLASSES (type);
int base_cnt = 0;
int n_base = i;
#endif
tree base, elems, access, offset, isvir;
- tree base_list, off_list, acc_list, isvir_list;
- static tree acc_pub = NULL_TREE;
- static tree acc_pro = NULL_TREE;
- static tree acc_pri = NULL_TREE;
+ tree elt, elts = NULL_TREE;
+ static tree base_info_type_node;
- if (acc_pub == NULL_TREE)
+ if (base_info_type_node == NULL_TREE)
{
- acc_pub = lookup_field (__class_desc_type_node,
- get_identifier("_RTTI_ACCESS_PUBLIC"), 0, 0);
- acc_pro = lookup_field (__class_desc_type_node,
- get_identifier("_RTTI_ACCESS_PROTECTED"), 0, 0);
- acc_pri = lookup_field (__class_desc_type_node,
- get_identifier("_RTTI_ACCESS_PRIVATE"), 0, 0);
+ tree fields [4];
+
+ /* A reasonably close approximation of __class_type_info::base_info */
+
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+ base_info_type_node = make_lang_type (RECORD_TYPE);
+
+ /* Actually const __user_type_info * */
+ fields [0] = build_lang_field_decl
+ (FIELD_DECL, NULL_TREE,
+ build_pointer_type (build_type_variant (type_info_type_node, 1, 0)));
+ fields [1] = build_lang_field_decl
+ (FIELD_DECL, NULL_TREE, sizetype);
+ DECL_BIT_FIELD (fields[1]) = 1;
+ DECL_FIELD_SIZE (fields[1]) = 29;
+
+ fields [2] = build_lang_field_decl
+ (FIELD_DECL, NULL_TREE, boolean_type_node);
+ DECL_BIT_FIELD (fields[2]) = 1;
+ DECL_FIELD_SIZE (fields[2]) = 1;
+
+ /* Actually enum access */
+ fields [3] = build_lang_field_decl
+ (FIELD_DECL, NULL_TREE, integer_type_node);
+ DECL_BIT_FIELD (fields[3]) = 1;
+ DECL_FIELD_SIZE (fields[3]) = 2;
+
+ finish_builtin_type (base_info_type_node, "__base_info", fields,
+ 3, ptr_type_node);
+ pop_obstacks ();
}
- base_list = build_tree_list (NULL_TREE, integer_zero_node);
- off_list = build_tree_list (NULL_TREE, integer_zero_node);
- acc_list = build_tree_list (NULL_TREE, integer_zero_node);
- isvir_list = build_tree_list (NULL_TREE, integer_zero_node);
while (--i >= 0)
{
tree binfo = TREE_VEC_ELT (binfos, i);
- base = build_t_desc (BINFO_TYPE (binfo), 1);
+ expand_expr_stmt (get_typeid_1 (BINFO_TYPE (binfo)));
+ base = decay_conversion (get_tinfo_var (BINFO_TYPE (binfo)));
+
if (TREE_VIA_VIRTUAL (binfo))
{
tree t = BINFO_TYPE (binfo);
offset = BINFO_OFFSET (binfo);
if (TREE_VIA_PUBLIC (binfo))
- access = acc_pub;
+ access = access_public_node;
else if (TREE_VIA_PROTECTED (binfo))
- access = acc_pro;
+ access = access_protected_node;
else
- access = acc_pri;
+ access = access_private_node;
if (TREE_VIA_VIRTUAL (binfo))
- isvir = build_int_2 (1, 0);
+ isvir = boolean_true_node;
else
- isvir = build_int_2 (0, 0);
-
- base_list = tree_cons (NULL_TREE, base, base_list);
- isvir_list = tree_cons (NULL_TREE, isvir, isvir_list);
- acc_list = tree_cons (NULL_TREE, access, acc_list);
- off_list = tree_cons (NULL_TREE, offset, off_list);
+ isvir = boolean_false_node;
+
+ elt = build
+ (CONSTRUCTOR, base_info_type_node, NULL_TREE, tree_cons
+ (NULL_TREE, base, tree_cons
+ (NULL_TREE, offset, tree_cons
+ (NULL_TREE, isvir, tree_cons
+ (NULL_TREE, access, NULL_TREE)))));
+ TREE_HAS_CONSTRUCTOR (elt) = TREE_CONSTANT (elt) = TREE_STATIC (elt) = 1;
+ elts = tree_cons (NULL_TREE, elt, elts);
base_cnt++;
}
#if 0
while (vb)
{
tree b;
- access = acc_pub;
+ access = access_public_node;
while (--i >= 0)
{
b = TREE_VEC_ELT (binfos, i);
if (BINFO_TYPE (vb) == BINFO_TYPE (b) && TREE_VIA_VIRTUAL (b))
{
if (TREE_VIA_PUBLIC (b))
- access = acc_pub;
+ access = access_public_node;
else if (TREE_VIA_PROTECTED (b))
- access = acc_pro;
+ access = access_protected_node;
else
- access = acc_pri;
+ access = access_private_node;
break;
}
}
vb = TREE_CHAIN (vb);
}
#endif
- base_list = finish_table (NULL_TREE, build_pointer_type (__t_desc_type_node),
- base_list, 0);
- off_list = finish_table (NULL_TREE, integer_type_node,
- off_list, 0);
- isvir_list = finish_table (NULL_TREE, integer_type_node,
- isvir_list, 0);
- acc_list = finish_table (NULL_TREE, __access_mode_type_node,
- acc_list, 0);
-
- name_string = combine_strings (build_string (IDENTIFIER_LENGTH (tname)+1, IDENTIFIER_POINTER (tname)));
+ name = build_overload_name (type, 1, 1);
+ name_string = combine_strings (build_string (strlen (name), name));
- elems = tree_cons (NULL_TREE, name_string,
- tree_cons (NULL_TREE, default_conversion (base_list),
- tree_cons (NULL_TREE, default_conversion (off_list),
- tree_cons (NULL_TREE, default_conversion (isvir_list),
- tree_cons (NULL_TREE, default_conversion (acc_list),
- tree_cons (NULL_TREE, build_int_2 (base_cnt, 0), NULL_TREE))))));
+ {
+ tree arrtype = build_array_type (base_info_type_node, NULL_TREE);
+ elts = build (CONSTRUCTOR, arrtype, NULL_TREE, elts);
+ TREE_HAS_CONSTRUCTOR (elts) = TREE_CONSTANT (elts) =
+ TREE_STATIC (elts) = 1;
+ complete_array_type (arrtype, elts, 1);
+ }
- return build_generic_desc (tdecl, __class_desc_type_node, elems);
-}
+ elems = tree_cons
+ (NULL_TREE, decay_conversion (tdecl), tree_cons
+ (NULL_TREE, decay_conversion (name_string), tree_cons
+ (NULL_TREE, decay_conversion (elts), tree_cons
+ (NULL_TREE, build_int_2 (base_cnt, 0), NULL_TREE))));
-/* Build an initializer for a __pointer_type_info node. */
-static tree
-build_ptr_desc (tdecl, type)
- tree tdecl;
- tree type;
-{
- tree t, elems;
+ fn = get_identifier ("__rtti_class");
+ if (IDENTIFIER_GLOBAL_VALUE (fn))
+ fn = IDENTIFIER_GLOBAL_VALUE (fn);
+ else
+ {
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+ tmp = tree_cons
+ (NULL_TREE, ptr_type_node, tree_cons
+ (NULL_TREE, const_string_type_node, tree_cons
+ (NULL_TREE, build_pointer_type (base_info_type_node), tree_cons
+ (NULL_TREE, sizetype, void_list_node))));
+ tmp = build_function_type (void_type_node, tmp);
+
+ fn = build_lang_decl (FUNCTION_DECL, fn, tmp);
+ DECL_EXTERNAL (fn) = 1;
+ TREE_PUBLIC (fn) = 1;
+ DECL_ARTIFICIAL (fn) = 1;
+ pushdecl_top_level (fn);
+ make_function_rtl (fn);
+ pop_obstacks ();
+ }
- t = TREE_TYPE (type);
- t = build_t_desc (t, 1);
- t = build_indirect_ref (t, NULL);
- elems = tree_cons (NULL_TREE, t, NULL_TREE);
- return build_generic_desc (tdecl, __ptr_desc_type_node, elems);
+ fn = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
+ decay_conversion (fn), elems, 0);
+ TREE_SIDE_EFFECTS (fn) = 1;
+ expand_expr_stmt (fn);
}
-/* Build an initializer for a __attr_type_info node. */
-static tree
-build_attr_desc (tdecl, type)
+/* Build an initializer for a __pointer_type_info node. */
+static void
+expand_ptr_desc (tdecl, type)
tree tdecl;
tree type;
{
- tree elems, t, attrval;
+ tree t, elems, fn;
+ char *name = build_overload_name (type, 1, 1);
+ tree name_string = combine_strings (build_string (strlen (name), name));
- if (TYPE_READONLY (type))
- {
- if (TYPE_VOLATILE (type))
- attrval = lookup_field (__attr_desc_type_node,
- get_identifier("_RTTI_ATTR_CONSTVOL"), 0, 0);
- else
- attrval = lookup_field (__attr_desc_type_node,
- get_identifier("_RTTI_ATTR_CONST"), 0, 0);
- }
+ type = TREE_TYPE (type);
+ expand_expr_stmt (get_typeid_1 (type));
+ t = decay_conversion (get_tinfo_var (type));
+ elems = tree_cons
+ (NULL_TREE, decay_conversion (tdecl), tree_cons
+ (NULL_TREE, decay_conversion (name_string), tree_cons
+ (NULL_TREE, t, NULL_TREE)));
+
+ fn = get_identifier ("__rtti_ptr");
+ if (IDENTIFIER_GLOBAL_VALUE (fn))
+ fn = IDENTIFIER_GLOBAL_VALUE (fn);
else
{
- if (TYPE_VOLATILE (type))
- attrval = lookup_field (__attr_desc_type_node,
- get_identifier("_RTTI_ATTR_VOLATILE"), 0, 0);
+ tree tmp;
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+ tmp = tree_cons
+ (NULL_TREE, ptr_type_node, tree_cons
+ (NULL_TREE, const_string_type_node, tree_cons
+ (NULL_TREE, build_pointer_type (type_info_type_node),
+ void_list_node)));
+ tmp = build_function_type (void_type_node, tmp);
+
+ fn = build_lang_decl (FUNCTION_DECL, fn, tmp);
+ DECL_EXTERNAL (fn) = 1;
+ TREE_PUBLIC (fn) = 1;
+ DECL_ARTIFICIAL (fn) = 1;
+ pushdecl_top_level (fn);
+ make_function_rtl (fn);
+ pop_obstacks ();
}
- t = build_t_desc (TYPE_MAIN_VARIANT (type), 1);
- t = build_indirect_ref (t , NULL);
- elems = tree_cons (NULL_TREE, attrval, tree_cons (NULL_TREE, t, NULL_TREE));
- return build_generic_desc (tdecl, __attr_desc_type_node, elems);
-}
-
-/* Build an initializer for a __func_type_info node. */
-static tree
-build_func_desc (tdecl)
- tree tdecl;
-{
- tree elems, name_string;
- tree tname = DECL_NAME (tdecl);
- name_string = combine_strings (build_string
- (IDENTIFIER_LENGTH (tname)+1, IDENTIFIER_POINTER (tname)));
- elems = name_string;
- return build_generic_desc (tdecl, __func_desc_type_node, elems);
+ fn = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
+ decay_conversion (fn), elems, 0);
+ TREE_SIDE_EFFECTS (fn) = 1;
+ expand_expr_stmt (fn);
}
-/* Build an initializer for a __ptmf_type_info node. */
-static tree
-build_ptmf_desc (tdecl)
- tree tdecl;
-{
- tree elems, name_string;
- tree tname = DECL_NAME (tdecl);
-
- name_string = combine_strings (build_string
- (IDENTIFIER_LENGTH (tname)+1, IDENTIFIER_POINTER (tname)));
- elems = name_string;
- return build_generic_desc (tdecl, __ptmf_desc_type_node, elems);
-}
-
-/* Build an initializer for a __ptmd_type_info node. */
-static tree
-build_ptmd_desc (tdecl, type)
- tree tdecl;
- tree type;
-{
- tree tc, t, elems;
- tc = build_t_desc (TYPE_OFFSET_BASETYPE (type), 1);
- tc = build_indirect_ref (tc , NULL);
- t = build_t_desc (TREE_TYPE (type), 1);
- t = build_indirect_ref (t , NULL);
- elems = tree_cons (NULL_TREE, tc,
- tree_cons (NULL_TREE, t, NULL_TREE));
- return build_generic_desc (tdecl, __ptmd_desc_type_node, elems);
-}
-
-struct uninst_st {
- tree type;
- struct uninst_st *next;
-};
-typedef struct uninst_st uninst_node;
-static uninst_node * uninst_desc = (uninst_node *)NULL;
+/* Build an initializer for a __attr_type_info node. */
static void
-add_uninstantiated_desc (type)
+expand_attr_desc (tdecl, type)
+ tree tdecl;
tree type;
{
- uninst_node *t;
+ tree elems, t, fn;
+ char *name = build_overload_name (type, 1, 1);
+ tree name_string = combine_strings (build_string (strlen (name), name));
+ tree attrval = build_int_2
+ (TYPE_READONLY (type) | TYPE_VOLATILE (type) * 2, 0);
+
+ expand_expr_stmt (get_typeid_1 (TYPE_MAIN_VARIANT (type)));
+ t = decay_conversion (get_tinfo_var (TYPE_MAIN_VARIANT (type)));
+ elems = tree_cons
+ (NULL_TREE, decay_conversion (tdecl), tree_cons
+ (NULL_TREE, decay_conversion (name_string), tree_cons
+ (NULL_TREE, attrval, tree_cons (NULL_TREE, t, NULL_TREE))));
+
+ fn = get_identifier ("__rtti_attr");
+ if (IDENTIFIER_GLOBAL_VALUE (fn))
+ fn = IDENTIFIER_GLOBAL_VALUE (fn);
+ else
+ {
+ tree tmp;
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+ tmp = tree_cons
+ (NULL_TREE, ptr_type_node, tree_cons
+ (NULL_TREE, const_string_type_node, tree_cons
+ (NULL_TREE, integer_type_node, tree_cons
+ (NULL_TREE, build_pointer_type (type_info_type_node),
+ void_list_node))));
+ tmp = build_function_type (void_type_node, tmp);
+
+ fn = build_lang_decl (FUNCTION_DECL, fn, tmp);
+ DECL_EXTERNAL (fn) = 1;
+ TREE_PUBLIC (fn) = 1;
+ DECL_ARTIFICIAL (fn) = 1;
+ pushdecl_top_level (fn);
+ make_function_rtl (fn);
+ pop_obstacks ();
+ }
- t = (uninst_node *) xmalloc (sizeof (struct uninst_st));
- t->type = type;
- t->next = uninst_desc;
- uninst_desc = t;
+ fn = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
+ decay_conversion (fn), elems, 0);
+ TREE_SIDE_EFFECTS (fn) = 1;
+ expand_expr_stmt (fn);
}
-/* We may choose to link the emitting of certain high use TDs for certain
- objects, we do that here. Return the type to link against if such a
- link exists, otherwise just return TYPE. */
+/* Build an initializer for a type_info node that just has a name. */
-static tree
-get_def_to_follow (type)
- tree type;
-{
-#if 0
- /* For now we don't lay out T&, T* TDs with the main TD for the object. */
- /* Let T* and T& be written only when T is written (if T is an aggr).
- We do this for const, but not for volatile, since volatile
- is rare and const is not. */
- if (!TYPE_VOLATILE (taggr)
- && (TREE_CODE (taggr) == POINTER_TYPE
- || TREE_CODE (taggr) == REFERENCE_TYPE)
- && IS_AGGR_TYPE (TREE_TYPE (taggr)))
- taggr = TREE_TYPE (taggr);
-#endif
- return type;
-}
-
-/* build a general type_info node. */
-tree
-build_t_desc (type, definition)
+static void
+expand_generic_desc (tdecl, type, fnname)
+ tree tdecl;
tree type;
- int definition;
+ char *fnname;
{
- tree tdecl, tname;
- tree t, taggr;
-
- if (__ptmd_desc_type_node == NULL_TREE)
- {
- init_type_desc();
- if (__ptmd_desc_type_node)
- {
- for ( ; uninst_desc; uninst_desc = uninst_desc->next )
- build_t_desc (uninst_desc->type, 1);
- }
- }
- if (__t_desc_type_node == NULL_TREE)
- {
- static int warned = 0;
- if (! warned)
- {
- cp_error ("failed to build type descriptor node of '%T', maybe <typeinfo> not included", type);
- }
- warned = 1;
- return error_mark_node;
- }
- if (__ptmd_desc_type_node == NULL_TREE)
- {
- add_uninstantiated_desc (type);
- definition = 0;
- }
-
- push_obstacks (&permanent_obstack, &permanent_obstack);
- tname = build_t_desc_overload (type);
-
- if (!IDENTIFIER_AS_DESC (tname))
+ char *name = build_overload_name (type, 1, 1);
+ tree name_string = combine_strings (build_string (strlen (name), name));
+ tree elems = tree_cons
+ (NULL_TREE, decay_conversion (tdecl), tree_cons
+ (NULL_TREE, decay_conversion (name_string), NULL_TREE));
+
+ tree fn = get_identifier (fnname);
+ if (IDENTIFIER_GLOBAL_VALUE (fn))
+ fn = IDENTIFIER_GLOBAL_VALUE (fn);
+ else
{
- tdecl = build_decl (VAR_DECL, tname, __t_desc_type_node);
- DECL_EXTERNAL (tdecl) = 1;
- TREE_PUBLIC (tdecl) = 1;
- tdecl = pushdecl_top_level (tdecl);
- SET_IDENTIFIER_AS_DESC (tname, build_unary_op (ADDR_EXPR, tdecl, 0));
- if (!definition)
- cp_finish_decl (tdecl, NULL_TREE, NULL_TREE, 0, 0);
+ tree tmp;
+ push_obstacks (&permanent_obstack, &permanent_obstack);
+ tmp = tree_cons
+ (NULL_TREE, ptr_type_node, tree_cons
+ (NULL_TREE, const_string_type_node, void_list_node));
+ tmp = build_function_type (void_type_node, tmp);
+
+ fn = build_lang_decl (FUNCTION_DECL, fn, tmp);
+ DECL_EXTERNAL (fn) = 1;
+ TREE_PUBLIC (fn) = 1;
+ DECL_ARTIFICIAL (fn) = 1;
+ pushdecl_top_level (fn);
+ make_function_rtl (fn);
+ pop_obstacks ();
}
- else
- tdecl = TREE_OPERAND (IDENTIFIER_AS_DESC (tname), 0);
- /* If it's not a definition, don't do anything more. */
- if (!definition)
- return IDENTIFIER_AS_DESC (tname);
+ fn = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
+ decay_conversion (fn), elems, 0);
+ TREE_SIDE_EFFECTS (fn) = 1;
+ expand_expr_stmt (fn);
+}
- /* If it has already been written, don't to anything more. */
- /* Should this be on tdecl? */
- if (TREE_ASM_WRITTEN (IDENTIFIER_AS_DESC (tname)))
- return IDENTIFIER_AS_DESC (tname);
+/* Generate the code for a type_info initialization function.
+ Note that we take advantage of the passage
- /* If we previously defined it, return the defined result. */
- if (DECL_INITIAL (tdecl))
- return IDENTIFIER_AS_DESC (tname);
-
- taggr = get_def_to_follow (type);
+ 5.2.7 Type identification [expr.typeid]
+
+ Whether or not the destructor is called for the type_info object at the
+ end of the program is unspecified.
- /* If we know that we don't need to write out this type's
- vtable, then don't write out it's type_info. Somebody
- else will take care of that. */
- if (IS_AGGR_TYPE (taggr) && CLASSTYPE_VFIELD (taggr))
- {
- /* Let's play follow the vtable. */
- TREE_PUBLIC (tdecl) = CLASSTYPE_INTERFACE_KNOWN (taggr);
- DECL_EXTERNAL (tdecl) = CLASSTYPE_INTERFACE_ONLY (taggr);
- }
- else
- {
- DECL_EXTERNAL (tdecl) = 0;
- TREE_PUBLIC (tdecl) = (definition > 1);
- }
+ and don't bother to arrange for these objects to be destroyed. It
+ doesn't matter, anyway, since the destructors don't do anything.
+
+ This must only be called from toplevel (i.e. from finish_file)! */
- if (DECL_EXTERNAL (tdecl))
- return IDENTIFIER_AS_DESC (tname);
+void
+synthesize_tinfo_fn (fndecl)
+ tree fndecl;
+{
+ tree type = TREE_TYPE (DECL_NAME (fndecl));
+ tree tmp, addr;
- /* Show that we are defining the t_desc for this type. */
- DECL_INITIAL (tdecl) = error_mark_node;
- t = DECL_CONTEXT (tdecl);
- if ( t && TREE_CODE_CLASS (TREE_CODE (t)) == 't')
- pushclass (t, 2);
+ tree tdecl = get_tinfo_var (type);
+ DECL_EXTERNAL (tdecl) = 0;
+ TREE_STATIC (tdecl) = 1;
+ DECL_COMMON (tdecl) = 1;
+ TREE_USED (tdecl) = 1;
+ DECL_ALIGN (tdecl) = TYPE_ALIGN (ptr_type_node);
+ cp_finish_decl (tdecl, NULL_TREE, NULL_TREE, 0, 0);
+
+ start_function (NULL_TREE, fndecl, NULL_TREE, NULL_TREE, 1);
+ store_parm_decls ();
+ clear_last_expr ();
+ push_momentary ();
+
+ /* If the first word of the array (the vtable) is non-zero, we've already
+ initialized the object, so don't do it again. */
+ addr = decay_conversion (tdecl);
+ tmp = convert (build_pointer_type (ptr_type_node), addr);
+ tmp = build_indirect_ref (tmp, 0);
+ tmp = build_binary_op (EQ_EXPR, tmp, integer_zero_node, 1);
+ expand_start_cond (tmp, 0);
if (TYPE_VOLATILE (type) || TYPE_READONLY (type))
- t = build_attr_desc (tdecl, type);
+ expand_attr_desc (tdecl, type);
else if (TREE_CODE (type) == ARRAY_TYPE)
- t = build_ptr_desc (tdecl, type);
+ expand_generic_desc (tdecl, type, "__rtti_array");
else if (TREE_CODE (type) == POINTER_TYPE)
{
if (TREE_CODE (TREE_TYPE (type)) == OFFSET_TYPE)
- {
- type = TREE_TYPE (type);
- t = build_ptmd_desc (tdecl, type);
- }
+ expand_generic_desc (tdecl, type, "__rtti_ptmd");
+ else if (TREE_CODE (TREE_TYPE (type)) == METHOD_TYPE)
+ expand_generic_desc (tdecl, type, "__rtti_ptmf");
else
- {
- t = build_ptr_desc (tdecl, type);
- }
+ expand_ptr_desc (tdecl, type);
}
- else if (TYPE_BUILT_IN (type))
- t = build_bltn_desc (tdecl, type);
+ else if (TYPE_PTRMEMFUNC_P (type))
+ expand_generic_desc (tdecl, type, "__rtti_ptmf");
else if (IS_AGGR_TYPE (type))
{
- if (TYPE_PTRMEMFUNC_P (type))
- t = build_ptmf_desc (tdecl);
+ if (CLASSTYPE_N_BASECLASSES (type) == 0)
+ expand_generic_desc (tdecl, type, "__rtti_user");
+ else if (! TYPE_USES_COMPLEX_INHERITANCE (type)
+ && (TREE_VIA_PUBLIC
+ (TREE_VEC_ELT (TYPE_BINFO_BASETYPES (type), 0))))
+ expand_si_desc (tdecl, type);
else
- t = build_class_desc (tdecl, type);
+ expand_class_desc (tdecl, type);
}
+ else if (TREE_CODE (type) == ENUMERAL_TYPE)
+ expand_generic_desc (tdecl, type, "__rtti_user");
else if (TREE_CODE (type) == FUNCTION_TYPE)
- t = build_func_desc (tdecl);
- else
- t = build_user_desc (tdecl);
+ expand_generic_desc (tdecl, type, "__rtti_func");
+ else
+ my_friendly_abort (252);
- pop_obstacks ();
- return t;
+ expand_end_cond ();
+
+ /* OK, now return the type_info object. */
+ tmp = convert (build_pointer_type (type_info_type_node), addr);
+ tmp = build_indirect_ref (tmp, 0);
+ c_expand_return (tmp);
+ finish_function (lineno, 0, 0);
}
#if 0