diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index d9f06b5a1cc..18814cf207b 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,35 @@ +2002-06-30 Nathan Sidwell + + * cp-tree.h (CPTI_TINFO_DECL_TYPE): Replace with ... + (CPTI_TYPE_INFO_PTR_TYPE): ... this. + (tinfo_decl_type): Replace with ... + (type_info_ptr_type): ... this. + (import_export_tinfo): Declare. + (tinfo_decl_p): Rename to ... + (unemitted_tinfo_decl_p): ... this. + * decl2.c (import_export_decl): Break out tinfo handling into ... + (import_export_tinfo): ... here. New function. + (finish_file): Adjust. + * rtti.c (TINFO_REAL_NAME): New macro. + (init_rtti_processing): Create the tinfo types. + (get_tinfo_decl_dynamic): Use type_info_ptr_type, get_tinfo_ptr. + (get_tinfo_decl): Adjust. + (get_tinfo_ptr): New function. + (get_type_id): Use it. + (tinfo_base_init): Create vtable decl here, if it doesn't exist. + (ptr_initializer): Use get_tinfo_ptr. + (ptm_initializer): Likewise. + (synthesize_tinfo_var): Break into ... + (get_pseudo_ti_init): ... this. Just create the initializer. + (get_pseudo_ti_desc): .. and this. + (create_real_tinfo_var): Remove. + (create_pseudo_type_info): Don't create the vtable decl here. + (get_vmi_pseudo_type_info): Remove. + (create_tinfo_types): Adjust. + (tinfo_decl_p): Rename to ... + (unemitted_tinfo_decl_p): ... here. Adjust. + (emit_tinfo_decl): Adjust. Create the initializer. + 2002-06-27 Mark Mitchell PR c++/6695 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 2c19c09a885..80b0f4378d8 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -567,7 +567,7 @@ enum cp_tree_index CPTI_STD, CPTI_ABI, CPTI_TYPE_INFO_TYPE, - CPTI_TINFO_DECL_TYPE, + CPTI_TYPE_INFO_PTR_TYPE, CPTI_ABORT_FNDECL, CPTI_GLOBAL_DELETE_FNDECL, CPTI_AGGR_TAG, @@ -654,7 +654,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX]; #define std_node cp_global_trees[CPTI_STD] #define abi_node cp_global_trees[CPTI_ABI] #define type_info_type_node cp_global_trees[CPTI_TYPE_INFO_TYPE] -#define tinfo_decl_type cp_global_trees[CPTI_TINFO_DECL_TYPE] +#define type_info_ptr_type cp_global_trees[CPTI_TYPE_INFO_PTR_TYPE] #define abort_fndecl cp_global_trees[CPTI_ABORT_FNDECL] #define global_delete_fndecl cp_global_trees[CPTI_GLOBAL_DELETE_FNDECL] #define current_aggr cp_global_trees[CPTI_AGGR_TAG] @@ -3935,6 +3935,7 @@ extern tree coerce_delete_type PARAMS ((tree)); extern void comdat_linkage PARAMS ((tree)); extern void import_export_vtable PARAMS ((tree, tree, int)); extern void import_export_decl PARAMS ((tree)); +extern void import_export_tinfo PARAMS ((tree, tree)); extern tree build_cleanup PARAMS ((tree)); extern void finish_file PARAMS ((void)); extern tree reparse_absdcl_as_expr PARAMS ((tree, tree)); @@ -4163,7 +4164,7 @@ extern tree get_tinfo_decl PARAMS((tree)); extern tree get_typeid PARAMS((tree)); extern tree build_dynamic_cast PARAMS((tree, tree)); extern void emit_support_tinfos PARAMS((void)); -extern int tinfo_decl_p PARAMS((tree, void *)); +extern int unemitted_tinfo_decl_p PARAMS((tree, void *)); extern int emit_tinfo_decl PARAMS((tree *, void *)); /* in search.c */ diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index eb1dd00a004..b37dc8cec57 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -2509,47 +2509,44 @@ import_export_decl (decl) else comdat_linkage (decl); } - else if (tinfo_decl_p (decl, 0)) - { - /* Here, we only decide whether or not the tinfo node should be - emitted with the vtable. The decl we're considering isn't - actually the one which gets emitted; that one is generated in - create_real_tinfo_var. */ - - tree ctype = TREE_TYPE (DECL_NAME (decl)); - - if (IS_AGGR_TYPE (ctype)) - import_export_class (ctype); - - if (IS_AGGR_TYPE (ctype) && CLASSTYPE_INTERFACE_KNOWN (ctype) - && TYPE_POLYMORPHIC_P (ctype) - /* If -fno-rtti, we're not necessarily emitting this stuff with - the class, so go ahead and emit it now. This can happen - when a class is used in exception handling. */ - && flag_rtti - /* If the type is a cv-qualified variant of a type, then we - must emit the tinfo function in this translation unit - since it will not be emitted when the vtable for the type - is output (which is when the unqualified version is - generated). */ - && same_type_p (ctype, TYPE_MAIN_VARIANT (ctype))) - { - DECL_NOT_REALLY_EXTERN (decl) - = ! CLASSTYPE_INTERFACE_ONLY (ctype); - DECL_COMDAT (decl) = 0; - } - else - { - DECL_NOT_REALLY_EXTERN (decl) = 1; - DECL_COMDAT (decl) = 1; - } - } else comdat_linkage (decl); DECL_INTERFACE_KNOWN (decl) = 1; } +/* Here, we only decide whether or not the tinfo node should be + emitted with the vtable. */ + +void +import_export_tinfo (decl, type) + tree decl; + tree type; +{ + if (DECL_INTERFACE_KNOWN (decl)) + return; + + if (IS_AGGR_TYPE (type)) + import_export_class (type); + + if (IS_AGGR_TYPE (type) && CLASSTYPE_INTERFACE_KNOWN (type) + && TYPE_POLYMORPHIC_P (type) + /* If -fno-rtti, we're not necessarily emitting this stuff with + the class, so go ahead and emit it now. This can happen when + a class is used in exception handling. */ + && flag_rtti) + { + DECL_NOT_REALLY_EXTERN (decl) = !CLASSTYPE_INTERFACE_ONLY (type); + DECL_COMDAT (decl) = 0; + } + else + { + DECL_NOT_REALLY_EXTERN (decl) = 1; + DECL_COMDAT (decl) = 1; + } + DECL_INTERFACE_KNOWN (decl) = 1; +} + tree build_cleanup (decl) tree decl; @@ -3344,7 +3341,7 @@ finish_file () /* Write out needed type info variables. Writing out one variable might cause others to be needed. */ - if (walk_globals (tinfo_decl_p, emit_tinfo_decl, /*data=*/0)) + if (walk_globals (unemitted_tinfo_decl_p, emit_tinfo_decl, /*data=*/0)) reconsider = 1; /* The list of objects with static storage duration is built up diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c index 317a44d53dd..3be44c5cdaa 100644 --- a/gcc/cp/rtti.c +++ b/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)); -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 . 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 () { @@ -76,8 +113,11 @@ init_rtti_processing () = xref_tag (class_type, get_identifier ("type_info"), /*attributes=*/NULL_TREE, 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 @@ -184,13 +224,12 @@ get_tinfo_decl_dynamic (exp) /* The RTTI information is at index -1. */ index = build_int_2 (-1 * TARGET_VTABLE_DATA_ENTRY_DISTANCE, -1); 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 @@ -264,9 +303,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) @@ -279,7 +318,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; } @@ -292,36 +331,44 @@ 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; 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 @@ -684,6 +731,7 @@ tinfo_base_init (desc, target) { tree init = NULL_TREE; tree name_decl; + tree vtable_ptr; { tree name_name; @@ -711,12 +759,41 @@ 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, TINFO_REAL_NAME (desc), + /*attributes=*/NULL_TREE, 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 * TARGET_VTABLE_DATA_ENTRY_DISTANCE), + 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); @@ -765,8 +842,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)); @@ -803,12 +879,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; @@ -929,81 +1004,63 @@ typeinfo_in_lib_p (type) } } -/* Generate a pseudo_type_info VAR_DECL suitable for the supplied - TARGET_TYPE and corresponding to PUBLIC_DECL. 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 (public_decl) - tree public_decl; +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; - tree target_type = TREE_TYPE (DECL_NAME (public_decl)); - my_friendly_assert (target_type != NULL_TREE, 20000120); - - /* Say we've dealt with it. */ - TREE_TYPE (DECL_NAME (public_decl)) = NULL_TREE; - - 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)) + if (TYPE_PTRMEMFUNC_P (type)) + return ptm_initializer (var_desc, type, non_public_p); + else if (var_desc == class_desc_type_node) { - 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)) - { - 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. */ @@ -1017,28 +1074,19 @@ synthesize_tinfo_var (public_decl) 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)); @@ -1049,88 +1097,23 @@ synthesize_tinfo_var (public_decl) 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, - public_decl, 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, public_decl, type, init, non_public) - tree target_type; - tree public_decl; - tree type; - tree init; - int non_public; -{ - static int count = 0; - tree decl; - tree hidden_name; - char hidden[30]; - tree name = DECL_ASSEMBLER_NAME (public_decl); - - /* 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 - || (DECL_COMDAT (public_decl) && !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 @@ -1139,7 +1122,10 @@ create_real_tinfo_var (target_type, public_decl, 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 @@ -1148,9 +1134,8 @@ create_real_tinfo_var (target_type, public_decl, 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; @@ -1167,29 +1152,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, get_identifier (real_name), - /*attributes=*/NULL_TREE, 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 * TARGET_VTABLE_DATA_ENTRY_DISTANCE), - 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); @@ -1203,53 +1165,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; + 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); + 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; } - desc = TREE_VEC_ELT (vmi_class_desc_type_node, num_bases); - - if (desc) - return desc; - - /* Add number of bases and trailing array of base_class_type_info. */ - array_domain = build_index_type (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; } /* Make sure the required builtin types exist for generating the type_info @@ -1258,15 +1263,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. */ @@ -1306,7 +1305,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, @@ -1314,7 +1313,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", @@ -1331,7 +1330,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, @@ -1340,8 +1339,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); @@ -1410,72 +1409,59 @@ 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 decl; + tree decl = *decl_ptr; + tree type = TREE_TYPE (DECL_NAME (decl)); + int non_public; + tree var_desc, var_init; - my_friendly_assert (TREE_TYPE (tinfo_decl) == tinfo_decl_type, 20000121); - - import_export_decl (tinfo_decl); - if (DECL_REALLY_EXTERN (tinfo_decl) || !DECL_NEEDED_P (tinfo_decl)) + import_export_tinfo (decl, type); + if (DECL_REALLY_EXTERN (decl) || !DECL_NEEDED_P (decl)) return 0; - create_tinfo_types (); - decl = synthesize_tinfo_var (tinfo_decl); + if (!doing_runtime && typeinfo_in_lib_p (type)) + return 0; + + non_public = 0; + var_desc = get_pseudo_ti_desc (type); + var_init = get_pseudo_ti_init (type, var_desc, &non_public); + DECL_EXTERNAL (decl) = 0; + TREE_PUBLIC (decl) = !non_public; + if (!non_public + && (flag_weak || (DECL_COMDAT (decl) && !typeinfo_in_lib_p (type)))) + comdat_linkage (decl); - return decl != 0; + DECL_INITIAL (decl) = var_init; + cp_finish_decl (decl, var_init, NULL_TREE, 0); + + /* Say we've dealt with it. */ + TREE_TYPE (DECL_NAME (decl)) = NULL_TREE; + + return 1; }