summaryrefslogtreecommitdiffstats
path: root/contrib/gcc/cp/rtti.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/gcc/cp/rtti.c')
-rw-r--r--contrib/gcc/cp/rtti.c614
1 files changed, 302 insertions, 312 deletions
diff --git a/contrib/gcc/cp/rtti.c b/contrib/gcc/cp/rtti.c
index 8c9b1c1..ae23234 100644
--- a/contrib/gcc/cp/rtti.c
+++ b/contrib/gcc/cp/rtti.c
@@ -1,5 +1,5 @@
/* RunTime Type Identification
- Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001
+ Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
Free Software Foundation, Inc.
Mostly written by Jason Merrill (jason@cygnus.com).
@@ -30,16 +30,46 @@ Boston, MA 02111-1307, USA. */
#include "assert.h"
#include "toplev.h"
+/* C++ returns type information to the user in struct type_info
+ objects. We also use type information to implement dynamic_cast and
+ exception handlers. Type information for a particular type is
+ indicated with an ABI defined structure derived from type_info.
+ This would all be very straight forward, but for the fact that the
+ runtime library provides the definitions of the type_info structure
+ and the ABI defined derived classes. We cannot build declarations
+ of them directly in the compiler, but we need to layout objects of
+ their type. Somewhere we have to lie.
+
+ We define layout compatible POD-structs with compiler-defined names
+ and generate the appropriate initializations for them (complete
+ with explicit mention of their vtable). When we have to provide a
+ type_info to the user we reinterpret_cast the internal compiler
+ type to type_info. A well formed program can only explicitly refer
+ to the type_infos of complete types (& cv void). However, we chain
+ pointer type_infos to the pointed-to-type, and that can be
+ incomplete. We only need the addresses of such incomplete
+ type_info objects for static initialization.
+
+ The type information VAR_DECL of a type is held on the
+ IDENTIFIER_GLOBAL_VALUE of the type's mangled name. That VAR_DECL
+ will be the internal type. It will usually have the correct
+ internal type reflecting the kind of type it represents (pointer,
+ array, function, class, inherited class, etc). When the type it
+ represents is incomplete, it will have the internal type
+ corresponding to type_info. That will only happen at the end of
+ translation, when we are emitting the type info objects. */
+
/* 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. */
+/* The VAR_DECL of the vtable for the type_info derived class.
+ This is only filled in at the end of the translation. */
#define TINFO_VTABLE_DECL(NODE) TREE_VALUE (NODE)
-
-extern struct obstack permanent_obstack;
+/* The IDENTIFIER_NODE naming the real class. */
+#define TINFO_REAL_NAME(NODE) TREE_PURPOSE (NODE)
static tree build_headof PARAMS((tree));
static tree ifnonnull PARAMS((tree, tree));
@@ -48,7 +78,8 @@ static tree build_dynamic_cast_1 PARAMS((tree, tree));
static tree throw_bad_cast PARAMS((void));
static tree throw_bad_typeid PARAMS((void));
static tree get_tinfo_decl_dynamic PARAMS((tree));
-static bool typeid_ok_p PARAMS ((void));
+static tree get_tinfo_ptr PARAMS((tree));
+static bool typeid_ok_p PARAMS((void));
static int qualifier_flags PARAMS((tree));
static int target_incomplete_p PARAMS((tree));
static tree tinfo_base_init PARAMS((tree, tree));
@@ -59,15 +90,21 @@ static tree dfs_class_hint_mark PARAMS ((tree, void *));
static tree dfs_class_hint_unmark PARAMS ((tree, void *));
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, tree, int));
static tree create_pseudo_type_info PARAMS((const char *, int, ...));
-static tree get_vmi_pseudo_type_info PARAMS((int));
+static tree get_pseudo_ti_init PARAMS ((tree, tree, int *));
+static tree get_pseudo_ti_desc PARAMS((tree));
static void create_tinfo_types PARAMS((void));
static int typeinfo_in_lib_p PARAMS((tree));
static int doing_runtime = 0;
+
+/* Declare language defined type_info type and a pointer to const
+ type_info. This is incomplete here, and will be completed when
+ the user #includes <typeinfo>. There are language defined
+ restrictions on what can be done until that is included. Create
+ the internal versions of the ABI types. */
+
void
init_rtti_processing ()
{
@@ -75,8 +112,11 @@ init_rtti_processing ()
type_info_type_node = xref_tag
(class_type_node, get_identifier ("type_info"), 1);
pop_namespace ();
- tinfo_decl_type =
- build_qualified_type (type_info_type_node, TYPE_QUAL_CONST);
+ type_info_ptr_type =
+ build_pointer_type
+ (build_qualified_type (type_info_type_node, TYPE_QUAL_CONST));
+
+ create_tinfo_types ();
}
/* Given the expression EXP of type `class *', return the head of the
@@ -183,13 +223,12 @@ get_tinfo_decl_dynamic (exp)
/* The RTTI information is at index -1. */
index = integer_minus_one_node;
t = build_vtbl_ref (exp, index);
- TREE_TYPE (t) = build_pointer_type (tinfo_decl_type);
+ TREE_TYPE (t) = type_info_ptr_type;
return t;
}
- /* otherwise return the type_info for the static type of the expr. */
- exp = get_tinfo_decl (TYPE_MAIN_VARIANT (type));
- return build_unary_op (ADDR_EXPR, exp, 0);
+ /* Otherwise return the type_info for the static type of the expr. */
+ return get_tinfo_ptr (TYPE_MAIN_VARIANT (type));
}
static bool
@@ -263,9 +302,9 @@ tinfo_name (type)
return name_string;
}
-/* Returns a decl for the type_info variable for TYPE. You must
- arrange that the decl is mark_used, if actually use it --- decls in
- vtables are only used if the vtable is output. */
+/* Return a VAR_DECL for the internal ABI defined type_info object for
+ TYPE. You must arrange that the decl is mark_used, if actually use
+ it --- decls in vtables are only used if the vtable is output. */
tree
get_tinfo_decl (type)
@@ -278,7 +317,7 @@ get_tinfo_decl (type)
&& TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
{
error ("cannot create type information for type `%T' because its size is variable",
- type);
+ type);
return error_mark_node;
}
@@ -291,37 +330,45 @@ get_tinfo_decl (type)
name = mangle_typeinfo_for_type (type);
d = IDENTIFIER_GLOBAL_VALUE (name);
- if (d)
- /* OK */;
- else
+ if (!d)
{
- /* 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 that we'll
- erroneously think we know the dynamic type -- be careful in the
- runtime. */
- d = build_lang_decl (VAR_DECL, name, tinfo_decl_type);
+ tree var_desc = get_pseudo_ti_desc (type);
+
+ d = build_lang_decl (VAR_DECL, name, TINFO_PSEUDO_TYPE (var_desc));
DECL_ARTIFICIAL (d) = 1;
- DECL_ALIGN (d) = TYPE_ALIGN (ptr_type_node);
- DECL_USER_ALIGN (d) = 0;
TREE_READONLY (d) = 1;
TREE_STATIC (d) = 1;
DECL_EXTERNAL (d) = 1;
- TREE_PUBLIC (d) = 1;
- if (flag_weak || !typeinfo_in_lib_p (type))
- comdat_linkage (d);
SET_DECL_ASSEMBLER_NAME (d, name);
+ DECL_COMDAT (d) = 1;
cp_finish_decl (d, NULL_TREE, NULL_TREE, 0);
pushdecl_top_level (d);
+
/* Remember the type it is for. */
TREE_TYPE (name) = type;
- TREE_USED (name) = 1;
}
+
return d;
}
+/* Return a pointer to a type_info object describing TYPE, suitably
+ cast to the language defined type. */
+
+static tree
+get_tinfo_ptr (type)
+ tree type;
+{
+ tree exp = get_tinfo_decl (type);
+
+ /* Convert to type_info type. */
+ exp = build_unary_op (ADDR_EXPR, exp, 0);
+ exp = ocp_convert (type_info_ptr_type, exp, CONV_REINTERPRET, 0);
+
+ return exp;
+}
+
/* Return the type_info object for TYPE. */
tree
@@ -350,7 +397,7 @@ get_typeid (type)
if (!type)
return error_mark_node;
- return get_tinfo_decl (type);
+ return build_indirect_ref (get_tinfo_ptr (type), NULL);
}
/* Check whether TEST is null before returning RESULT. If TEST is used in
@@ -683,6 +730,7 @@ tinfo_base_init (desc, target)
{
tree init = NULL_TREE;
tree name_decl;
+ tree vtable_ptr;
{
tree name_name;
@@ -710,12 +758,40 @@ tinfo_base_init (desc, target)
cp_finish_decl (name_decl, name_string, NULL_TREE, 0);
pushdecl_top_level (name_decl);
}
-
- if (TINFO_VTABLE_DECL (desc))
+
+ vtable_ptr = TINFO_VTABLE_DECL (desc);
+ if (!vtable_ptr)
{
- tree vtbl_ptr = TINFO_VTABLE_DECL (desc);
- init = tree_cons (NULL_TREE, vtbl_ptr, init);
+ tree real_type;
+
+ push_nested_namespace (abi_node);
+ real_type = xref_tag (class_type_node, TINFO_REAL_NAME (desc), 1);
+ pop_nested_namespace (abi_node);
+
+ if (!COMPLETE_TYPE_P (real_type))
+ {
+ /* We never saw a definition of this type, so we need to
+ tell the compiler that this is an exported class, as
+ indeed all of the __*_type_info classes are. */
+ SET_CLASSTYPE_INTERFACE_KNOWN (real_type);
+ CLASSTYPE_INTERFACE_ONLY (real_type) = 1;
+ }
+
+ vtable_ptr = get_vtable_decl (real_type, /*complete=*/1);
+ vtable_ptr = build_unary_op (ADDR_EXPR, vtable_ptr, 0);
+
+ /* We need to point into the middle of the vtable. */
+ vtable_ptr = build
+ (PLUS_EXPR, TREE_TYPE (vtable_ptr), vtable_ptr,
+ size_binop (MULT_EXPR,
+ size_int (2),
+ TYPE_SIZE_UNIT (vtable_entry_type)));
+ TREE_CONSTANT (vtable_ptr) = 1;
+
+ TINFO_VTABLE_DECL (desc) = vtable_ptr;
}
+
+ init = tree_cons (NULL_TREE, vtable_ptr, init);
init = tree_cons (NULL_TREE, decay_conversion (name_decl), init);
@@ -764,8 +840,7 @@ ptr_initializer (desc, target, non_public_ptr)
}
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),
+ get_tinfo_ptr (TYPE_MAIN_VARIANT (to)),
init);
init = build (CONSTRUCTOR, NULL_TREE, NULL_TREE, nreverse (init));
@@ -802,12 +877,11 @@ ptm_initializer (desc, target, non_public_ptr)
}
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),
+ get_tinfo_ptr (TYPE_MAIN_VARIANT (to)),
init);
init = tree_cons (NULL_TREE,
- build_unary_op (ADDR_EXPR, get_tinfo_decl (klass), 0),
- init);
+ get_tinfo_ptr (klass),
+ init);
init = build (CONSTRUCTOR, NULL_TREE, NULL_TREE, nreverse (init));
TREE_HAS_CONSTRUCTOR (init) = TREE_CONSTANT (init) = TREE_STATIC (init) = 1;
@@ -928,77 +1002,63 @@ typeinfo_in_lib_p (type)
}
}
-/* 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. */
+/* Generate the initializer for the type info describing
+ TYPE. VAR_DESC is a . NON_PUBLIC_P is set non-zero, if the VAR_DECL
+ should not be exported from this object file. This should only be
+ called at the end of translation, when we know that no further
+ types will be completed. */
static tree
-synthesize_tinfo_var (target_type, real_name)
- tree target_type;
- tree real_name;
+get_pseudo_ti_init (type, var_desc, non_public_p)
+ tree type;
+ tree var_desc;
+ int *non_public_p;
{
- tree var_init = NULL_TREE;
- tree var_type = NULL_TREE;
- int non_public = 0;
-
- switch (TREE_CODE (target_type))
+ my_friendly_assert (at_eof, 20021120);
+ switch (TREE_CODE (type))
{
case POINTER_TYPE:
- if (TYPE_PTRMEM_P (target_type))
- {
- var_type = ptm_desc_type_node;
- var_init = ptm_initializer (var_type, target_type, &non_public);
- }
+ if (TYPE_PTRMEM_P (type))
+ return ptm_initializer (var_desc, type, non_public_p);
else
- {
- if (typeinfo_in_lib_p (target_type) && !doing_runtime)
- /* These are in the runtime. */
- return NULL_TREE;
- var_type = ptr_desc_type_node;
- var_init = ptr_initializer (var_type, target_type, &non_public);
- }
+ return ptr_initializer (var_desc, type, non_public_p);
break;
case ENUMERAL_TYPE:
- var_type = enum_desc_type_node;
- var_init = generic_initializer (var_type, target_type);
+ return generic_initializer (var_desc, type);
break;
case FUNCTION_TYPE:
- var_type = func_desc_type_node;
- var_init = generic_initializer (var_type, target_type);
+ return generic_initializer (var_desc, type);
break;
case ARRAY_TYPE:
- var_type = ary_desc_type_node;
- var_init = generic_initializer (var_type, target_type);
+ return generic_initializer (var_desc, type);
break;
case UNION_TYPE:
case RECORD_TYPE:
- if (TYPE_PTRMEMFUNC_P (target_type))
- {
- var_type = ptm_desc_type_node;
- var_init = ptm_initializer (var_type, target_type, &non_public);
- }
- else if (!COMPLETE_TYPE_P (target_type))
- {
- /* Emit a non-public class_type_info. */
- non_public = 1;
- var_type = class_desc_type_node;
- var_init = class_initializer (var_type, target_type, NULL_TREE);
- }
- else if (!CLASSTYPE_N_BASECLASSES (target_type))
+ if (TYPE_PTRMEMFUNC_P (type))
+ return ptm_initializer (var_desc, type, non_public_p);
+ else if (var_desc == class_desc_type_node)
{
- var_type = class_desc_type_node;
- var_init = class_initializer (var_type, target_type, NULL_TREE);
+ if (!COMPLETE_TYPE_P (type))
+ /* Emit a non-public class_type_info. */
+ *non_public_p = 1;
+ return class_initializer (var_desc, type, NULL_TREE);
}
+ else if (var_desc == si_class_desc_type_node)
+ {
+ tree base_binfos = BINFO_BASETYPES (TYPE_BINFO (type));
+ tree base_binfo = TREE_VEC_ELT (base_binfos, 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
{
- /* if this has a single public non-virtual base, it's easier */
- tree binfo = TYPE_BINFO (target_type);
+ int hint = class_hint_flags (type);
+ tree binfo = TYPE_BINFO (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. */
@@ -1012,28 +1072,19 @@ synthesize_tinfo_var (target_type, real_name)
if (TREE_PUBLIC (base_binfo))
flags |= 2;
- tinfo = get_tinfo_decl (BINFO_TYPE (base_binfo));
- tinfo = build_unary_op (ADDR_EXPR, tinfo, 0);
+ tinfo = get_tinfo_ptr (BINFO_TYPE (base_binfo));
if (TREE_VIA_VIRTUAL (base_binfo))
{
/* We store the vtable offset at which the virtual
base offset can be found. */
- offset = BINFO_VPTR_FIELD (binfo_for_vbase (BINFO_TYPE (base_binfo),
- target_type));
+ offset = BINFO_VPTR_FIELD
+ (binfo_for_vbase (BINFO_TYPE (base_binfo), type));
offset = convert (sizetype, offset);
flags |= 1;
}
else
offset = BINFO_OFFSET (base_binfo);
- /* 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;
-
/* combine offset and flags into one field */
offset = cp_build_binary_op (LSHIFT_EXPR, offset,
build_int_2 (8, 0));
@@ -1044,86 +1095,23 @@ synthesize_tinfo_var (target_type, real_name)
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
- {
- int hint = class_hint_flags (target_type);
-
- base_inits = build (CONSTRUCTOR, NULL_TREE, NULL_TREE, base_inits);
- base_inits = tree_cons (NULL_TREE, base_inits, NULL_TREE);
- /* Prepend the number of bases. */
- base_inits = tree_cons (NULL_TREE,
- build_int_2 (nbases, 0), base_inits);
- /* Prepend the hint flags. */
- base_inits = tree_cons (NULL_TREE,
- build_int_2 (hint, 0), base_inits);
- var_type = get_vmi_pseudo_type_info (nbases);
- }
- var_init = class_initializer (var_type, target_type, base_inits);
+ base_inits = build (CONSTRUCTOR,
+ NULL_TREE, NULL_TREE, base_inits);
+ base_inits = tree_cons (NULL_TREE, base_inits, NULL_TREE);
+ /* Prepend the number of bases. */
+ base_inits = tree_cons (NULL_TREE,
+ build_int_2 (nbases, 0), base_inits);
+ /* Prepend the hint flags. */
+ base_inits = tree_cons (NULL_TREE,
+ build_int_2 (hint, 0), base_inits);
+
+ return class_initializer (var_desc, type, base_inits);
}
break;
default:
- if (typeinfo_in_lib_p (target_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;
- }
- abort ();
+ return generic_initializer (var_desc, type);
}
-
- return create_real_tinfo_var (target_type,
- real_name, TINFO_PSEUDO_TYPE (var_type),
- var_init, non_public);
-}
-
-/* Create the real typeinfo variable. NON_PUBLIC indicates that we cannot
- make this variable public (comdat). */
-
-static tree
-create_real_tinfo_var (target_type, name, type, init, non_public)
- tree target_type;
- tree name;
- tree type;
- tree init;
- int non_public;
-{
- static int count = 0;
- tree decl;
- tree hidden_name;
- char hidden[30];
-
- /* We cannot give this the name NAME, as that already is globally
- bound to the tinfo_decl we originally created for this type in
- get_tinfo_decl. */
- sprintf (hidden, "__ti_%d", count++);
- hidden_name = get_identifier (hidden);
-
- decl = build_lang_decl (VAR_DECL, hidden_name,
- build_qualified_type (type, TYPE_QUAL_CONST));
- DECL_ARTIFICIAL (decl) = 1;
- TREE_READONLY (decl) = 1;
- TREE_STATIC (decl) = 1;
- DECL_EXTERNAL (decl) = 0;
-
- if (!non_public)
- {
- TREE_PUBLIC (decl) = 1;
- if (flag_weak || !typeinfo_in_lib_p (target_type))
- comdat_linkage (decl);
- }
- SET_DECL_ASSEMBLER_NAME (decl, name);
- DECL_INITIAL (decl) = init;
- cp_finish_decl (decl, init, NULL_TREE, 0);
- pushdecl_top_level (decl);
- TREE_USED (decl) = 1;
- return decl;
}
/* Generate the RECORD_TYPE containing the data layout of a type_info
@@ -1132,7 +1120,10 @@ create_real_tinfo_var (target_type, name, type, init, non_public)
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.
+ is the generated type and TINFO_VTABLE_NAME is the name of the
+ vtable. We have to delay generating the VAR_DECL of the vtable
+ until the end of the translation, when we'll have seen the library
+ definition, if there was one.
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
@@ -1141,9 +1132,8 @@ create_real_tinfo_var (target_type, name, type, init, non_public)
static tree
create_pseudo_type_info VPARAMS((const char *real_name, int ident, ...))
{
- tree real_type, pseudo_type;
+ tree pseudo_type;
char *pseudo_name;
- tree vtable_decl;
int ix;
tree fields[10];
tree field_decl;
@@ -1160,29 +1150,6 @@ create_pseudo_type_info VPARAMS((const char *real_name, int ident, ...))
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);
- if (! TYPE_SIZE (real_type))
- {
- /* We never saw a definition of this type, so we need to tell the
- compiler that this is an exported class, as indeed all of the
- __*_type_info classes are. */
- SET_CLASSTYPE_INTERFACE_KNOWN (real_type);
- CLASSTYPE_INTERFACE_ONLY (real_type) = 1;
- }
-
- vtable_decl = get_vtable_decl (real_type, /*complete=*/1);
- vtable_decl = build_unary_op (ADDR_EXPR, vtable_decl, 0);
-
- /* We need to point into the middle of the vtable. */
- vtable_decl = build (PLUS_EXPR,
- TREE_TYPE (vtable_decl),
- vtable_decl,
- size_binop (MULT_EXPR,
- size_int (2),
- TYPE_SIZE_UNIT (vtable_entry_type)));
- TREE_CONSTANT (vtable_decl) = 1;
-
/* First field is the pseudo type_info base class. */
fields[0] = build_decl (FIELD_DECL, NULL_TREE, ti_desc_type_node);
@@ -1196,53 +1163,96 @@ create_pseudo_type_info VPARAMS((const char *real_name, int ident, ...))
TYPE_HAS_CONSTRUCTOR (pseudo_type) = 1;
result = tree_cons (NULL_TREE, NULL_TREE, NULL_TREE);
- TINFO_VTABLE_DECL (result) = vtable_decl;
- TINFO_PSEUDO_TYPE (result) = pseudo_type;
+ TINFO_REAL_NAME (result) = get_identifier (real_name);
+ TINFO_PSEUDO_TYPE (result) =
+ cp_build_qualified_type (pseudo_type, TYPE_QUAL_CONST);
VA_CLOSE (ap);
return result;
}
-/* Return a descriptor for a vmi type with NUM_BASES bases. */
+/* Return a pseudo type info type node used to describe TYPE. TYPE
+ must be a complete type (or cv void), except at the end of the
+ translation unit. */
static tree
-get_vmi_pseudo_type_info (num_bases)
- int num_bases;
+get_pseudo_ti_desc (type)
+ tree type;
{
- tree desc;
- tree array_domain, base_array;
-
- if (TREE_VEC_LENGTH (vmi_class_desc_type_node) <= num_bases)
+ switch (TREE_CODE (type))
{
- 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;
+ case POINTER_TYPE:
+ return TYPE_PTRMEM_P (type) ? ptm_desc_type_node : 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))
+ {
+ my_friendly_assert (at_eof, 20020609);
+ return class_desc_type_node;
+ }
+ else if (!CLASSTYPE_N_BASECLASSES (type))
+ return class_desc_type_node;
+ else
+ {
+ tree base_binfo =
+ TREE_VEC_ELT (BINFO_BASETYPES (TYPE_BINFO (type)), 0);
+ int num_bases = BINFO_N_BASETYPES (TYPE_BINFO (type));
+
+ if (num_bases == 1
+ && TREE_PUBLIC (base_binfo)
+ && !TREE_VIA_VIRTUAL (base_binfo)
+ && integer_zerop (BINFO_OFFSET (base_binfo)))
+ /* single non-virtual public. */
+ 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;
- /* Add number of bases and trailing array of base_class_type_info. */
- 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);
-
- 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) = desc;
- return desc;
+ /* Add number of bases and trailing array of
+ base_class_type_info. */
+ 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;
+ }
}
/* Make sure the required builtin types exist for generating the type_info
@@ -1251,15 +1261,9 @@ get_vmi_pseudo_type_info (num_bases)
static void
create_tinfo_types ()
{
- tree ptr_type_info;
-
- if (bltn_desc_type_node)
- return;
- push_nested_namespace (abi_node);
+ my_friendly_assert (!ti_desc_type_node, 20020609);
- ptr_type_info = build_pointer_type
- (build_qualified_type
- (type_info_type_node, TYPE_QUAL_CONST));
+ push_nested_namespace (abi_node);
/* Create the internal type_info structure. This is used as a base for
the other structures. */
@@ -1299,7 +1303,7 @@ create_tinfo_types ()
This is really a descendant of __class_type_info. */
si_class_desc_type_node = create_pseudo_type_info
("__si_class_type_info", 0,
- build_decl (FIELD_DECL, NULL_TREE, ptr_type_info),
+ build_decl (FIELD_DECL, NULL_TREE, type_info_ptr_type),
NULL);
/* Base class internal helper. Pointer to base type, offset to base,
@@ -1307,7 +1311,7 @@ create_tinfo_types ()
{
tree fields[2];
- fields[0] = build_decl (FIELD_DECL, NULL_TREE, ptr_type_info);
+ fields[0] = build_decl (FIELD_DECL, NULL_TREE, type_info_ptr_type);
fields[1] = build_decl (FIELD_DECL, NULL_TREE, integer_types[itk_long]);
base_desc_type_node = make_aggr_type (RECORD_TYPE);
finish_builtin_type (base_desc_type_node, "__base_class_type_info_pseudo",
@@ -1324,7 +1328,7 @@ create_tinfo_types ()
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, ptr_type_info),
+ build_decl (FIELD_DECL, NULL_TREE, type_info_ptr_type),
NULL);
/* Pointer to member data type_info. Add qualifications flags,
@@ -1333,8 +1337,8 @@ create_tinfo_types ()
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, ptr_type_info),
- build_decl (FIELD_DECL, NULL_TREE, ptr_type_info),
+ 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);
@@ -1401,75 +1405,61 @@ emit_support_tinfos ()
definition emitted for it. */
int
-tinfo_decl_p (t, data)
+unemitted_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));
+ if (/* It's a var decl */
+ TREE_CODE (t) == VAR_DECL
+ /* whos name points back to itself */
+ && IDENTIFIER_GLOBAL_VALUE (DECL_NAME (t)) == t
+ /* whos name's type is non-null */
+ && TREE_TYPE (DECL_NAME (t))
+ /* and whos type is a struct */
+ && TREE_CODE (TREE_TYPE (t)) == RECORD_TYPE
+ /* with a first field of our pseudo type info */
+ && TREE_TYPE (TYPE_FIELDS (TREE_TYPE (t))) == ti_desc_type_node)
+ return 1;
+ return 0;
}
-/* 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
- definition might cause other definitions to be required.
-
- 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. */
+/* Finish a type info decl. DECL_PTR is a pointer to an unemitted
+ tinfo decl. Determine whether it needs emitting, and if so
+ generate the initializer. */
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);
+ tree decl = *decl_ptr;
+ tree type = TREE_TYPE (DECL_NAME (decl));
+ int non_public;
+ int in_library = typeinfo_in_lib_p (type);
+ tree var_desc, var_init;
- if (!DECL_NEEDED_P (tinfo_decl))
+ import_export_tinfo (decl, type, in_library);
+ if (DECL_REALLY_EXTERN (decl) || !DECL_NEEDED_P (decl))
return 0;
- /* Say we've dealt with it. */
- TREE_TYPE (DECL_NAME (tinfo_decl)) = NULL_TREE;
+
+ if (!doing_runtime && in_library)
+ return 0;
+
+ non_public = 0;
+ var_desc = get_pseudo_ti_desc (type);
+ var_init = get_pseudo_ti_init (type, var_desc, &non_public);
- create_tinfo_types ();
- decl = synthesize_tinfo_var (tinfo_type, DECL_ASSEMBLER_NAME (tinfo_decl));
+ DECL_EXTERNAL (decl) = 0;
+ TREE_PUBLIC (decl) = !non_public;
+ if (non_public)
+ DECL_COMDAT (decl) = 0;
+
+ DECL_INITIAL (decl) = var_init;
+ cp_finish_decl (decl, var_init, NULL_TREE, 0);
+ /* cp_finish_decl will have dealt with linkage. */
- return decl != 0;
+ /* Say we've dealt with it. */
+ TREE_TYPE (DECL_NAME (decl)) = NULL_TREE;
+
+ return 1;
}
OpenPOWER on IntegriCloud