2017-06-16 Nathan Sidwell Make rtti lazier * rtti.c (enum tinfo_kind): Add TK_DERIVED_TYPES, TK_VMI_CLASS_TYPES, TK_MAX. Delete TK_FIXED. (tinfo_names): New. (typeid_ok_p): Add quotes to error messages. Use get_tinfo_desc. (get_tinfo_decl): Use get_tinfo_desc. (get_pseudo_ti_init): Likewise. Adjust VMI construction. (create_pseudo_type_info): Delete. (get_pseudo_ti_index): Just determine the index. (get_tinfo_desc): New. Create all types lazily. (create_tinfo_types): Just allocate the descriptor array. (emit_support_tinfos): Use non-inserting type lookup. Set builtin location. Index: rtti.c =================================================================== --- rtti.c (revision 249255) +++ rtti.c (working copy) @@ -75,7 +75,8 @@ enum tinfo_kind { TK_TYPE_INFO_TYPE, /* abi::__type_info_pseudo */ TK_BASE_TYPE, /* abi::__base_class_type_info */ - TK_BUILTIN_TYPE, /* abi::__fundamental_type_info */ + TK_DERIVED_TYPES, /* Start of types derived from abi::__type_info */ + TK_BUILTIN_TYPE = TK_DERIVED_TYPES, /* abi::__fundamental_type_info */ TK_ARRAY_TYPE, /* abi::__array_type_info */ TK_FUNCTION_TYPE, /* abi::__function_type_info */ TK_ENUMERAL_TYPE, /* abi::__enum_type_info */ @@ -83,8 +84,26 @@ enum tinfo_kind TK_POINTER_MEMBER_TYPE, /* abi::__pointer_to_member_type_info */ TK_CLASS_TYPE, /* abi::__class_type_info */ TK_SI_CLASS_TYPE, /* abi::__si_class_type_info */ - TK_FIXED /* end of fixed descriptors. */ - /* ... abi::__vmi_type_info */ + TK_VMI_CLASS_TYPES, /* abi::__vmi_class_type_info */ + TK_MAX +}; + +/* Names of the tinfo types. Must be same order as TK enumeration + above. */ + +static const char *const tinfo_names[TK_MAX] = +{ + "__type_info", + "__base_class_type_info", + "__fundamental_type_info", + "__array_type_info", + "__function_type_info", + "__enum_type_info", + "__pointer_type_info", + "__pointer_to_member_type_info", + "__class_type_info", + "__si_class_type_info", + "__vmi_class_type_info" }; /* Helper macro to get maximum scalar-width of pointer or of the 'long'-type. @@ -115,9 +134,9 @@ static tree generic_initializer (tinfo_s static tree ptr_initializer (tinfo_s *, tree); static tree ptm_initializer (tinfo_s *, tree); static tree class_initializer (tinfo_s *, tree, unsigned, ...); -static void create_pseudo_type_info (int, const char *, ...); static tree get_pseudo_ti_init (tree, unsigned); static unsigned get_pseudo_ti_index (tree); +static tinfo_s *get_tinfo_desc (unsigned); static void create_tinfo_types (void); static bool typeinfo_in_lib_p (tree); @@ -289,30 +308,27 @@ get_tinfo_decl_dynamic (tree exp, tsubst static bool typeid_ok_p (void) { - tree pseudo_type_info, type_info_type; - if (! flag_rtti) { - error ("cannot use typeid with -fno-rtti"); + error ("cannot use % with -fno-rtti"); return false; } if (!COMPLETE_TYPE_P (const_type_info_type_node)) { - error ("must #include before using typeid"); + error ("must %<#include %> before using %"); return false; } - pseudo_type_info = (*tinfo_descs)[TK_TYPE_INFO_TYPE].type; - type_info_type = TYPE_MAIN_VARIANT (const_type_info_type_node); + tree pseudo = TYPE_MAIN_VARIANT (get_tinfo_desc (TK_TYPE_INFO_TYPE)->type); + tree real = TYPE_MAIN_VARIANT (const_type_info_type_node); /* Make sure abi::__type_info_pseudo has the same alias set as std::type_info. */ - if (! TYPE_ALIAS_SET_KNOWN_P (pseudo_type_info)) - TYPE_ALIAS_SET (pseudo_type_info) = get_alias_set (type_info_type); + if (! TYPE_ALIAS_SET_KNOWN_P (pseudo)) + TYPE_ALIAS_SET (pseudo) = get_alias_set (real); else - gcc_assert (TYPE_ALIAS_SET (pseudo_type_info) - == get_alias_set (type_info_type)); + gcc_assert (TYPE_ALIAS_SET (pseudo) == get_alias_set (real)); return true; } @@ -428,8 +444,8 @@ get_tinfo_decl (tree type) if (!d) { int ix = get_pseudo_ti_index (type); - tinfo_s *ti = &(*tinfo_descs)[ix]; - + const tinfo_s *ti = get_tinfo_desc (ix); + d = build_lang_decl (VAR_DECL, name, ti->type); SET_DECL_ASSEMBLER_NAME (d, name); /* Remember the type it is for. */ @@ -1105,7 +1121,7 @@ typeinfo_in_lib_p (tree type) static tree get_pseudo_ti_init (tree type, unsigned tk_index) { - tinfo_s *ti = &(*tinfo_descs)[tk_index]; + tinfo_s *ti = get_tinfo_desc (tk_index); gcc_assert (at_eof); switch (tk_index) @@ -1140,22 +1156,18 @@ get_pseudo_ti_init (tree type, unsigned int hint = ((CLASSTYPE_REPEATED_BASE_P (type) << 0) | (CLASSTYPE_DIAMOND_SHAPED_P (type) << 1)); tree binfo = TYPE_BINFO (type); - int nbases = BINFO_N_BASE_BINFOS (binfo); + unsigned nbases = BINFO_N_BASE_BINFOS (binfo); vec *base_accesses = BINFO_BASE_ACCESSES (binfo); tree offset_type = LONGPTR_T; - tree base_inits = NULL_TREE; - int ix; vec *init_vec = NULL; - constructor_elt *e; - gcc_assert (tk_index >= TK_FIXED); + gcc_assert (tk_index - TK_VMI_CLASS_TYPES + 1 == nbases); vec_safe_grow (init_vec, nbases); /* Generate the base information initializer. */ - for (ix = nbases; ix--;) + for (unsigned ix = nbases; ix--;) { tree base_binfo = BINFO_BASE_BINFO (binfo, ix); - tree base_init; int flags = 0; tree tinfo; tree offset; @@ -1185,12 +1197,12 @@ get_pseudo_ti_init (tree type, unsigned vec_alloc (v, 2); CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, tinfo); CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, offset); - base_init = build_constructor (init_list_type_node, v); - e = &(*init_vec)[ix]; + tree base_init = build_constructor (init_list_type_node, v); + constructor_elt *e = &(*init_vec)[ix]; e->index = NULL_TREE; e->value = base_init; } - base_inits = build_constructor (init_list_type_node, init_vec); + tree base_inits = build_constructor (init_list_type_node, init_vec); /* get_tinfo_ptr might have reallocated the tinfo_descs vector. */ ti = &(*tinfo_descs)[tk_index]; @@ -1202,69 +1214,6 @@ get_pseudo_ti_init (tree type, unsigned } } -/* Generate the RECORD_TYPE containing the data layout of a type_info - derivative as used by the runtime. This layout must be consistent with - that defined in the runtime support. Also generate the VAR_DECL for the - 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_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 - NULL. */ - -static void -create_pseudo_type_info (int tk, const char *real_name, ...) -{ - tinfo_s *ti; - tree pseudo_type; - char *pseudo_name; - tree fields; - tree field_decl; - va_list ap; - - va_start (ap, real_name); - - /* Generate the pseudo type name. */ - pseudo_name = (char *) alloca (strlen (real_name) + 30); - strcpy (pseudo_name, real_name); - strcat (pseudo_name, "_pseudo"); - if (tk >= TK_FIXED) - sprintf (pseudo_name + strlen (pseudo_name), "%d", tk - TK_FIXED); - - /* First field is the pseudo type_info base class. */ - fields = build_decl (input_location, - FIELD_DECL, NULL_TREE, - (*tinfo_descs)[TK_TYPE_INFO_TYPE].type); - - /* Now add the derived fields. */ - while ((field_decl = va_arg (ap, tree))) - { - DECL_CHAIN (field_decl) = fields; - fields = field_decl; - } - - /* Create the pseudo type. */ - pseudo_type = make_class_type (RECORD_TYPE); - finish_builtin_struct (pseudo_type, pseudo_name, fields, NULL_TREE); - CLASSTYPE_AS_BASE (pseudo_type) = pseudo_type; - - ti = &(*tinfo_descs)[tk]; - ti->type = cp_build_qualified_type (pseudo_type, TYPE_QUAL_CONST); - ti->name = get_identifier (real_name); - ti->vtable = NULL_TREE; - - /* Pretend this is public so determine_visibility doesn't give vtables - internal linkage. */ - TREE_PUBLIC (TYPE_MAIN_DECL (ti->type)) = 1; - - va_end (ap); -} - /* Return the index of 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. */ @@ -1299,23 +1248,16 @@ get_pseudo_ti_index (tree type) case UNION_TYPE: case RECORD_TYPE: if (TYPE_PTRMEMFUNC_P (type)) - { - ix = TK_POINTER_MEMBER_TYPE; - break; - } + ix = TK_POINTER_MEMBER_TYPE; else if (!COMPLETE_TYPE_P (type)) { if (!at_eof) cxx_incomplete_type_error (NULL_TREE, type); ix = TK_CLASS_TYPE; - break; } else if (!TYPE_BINFO (type) || !BINFO_N_BASE_BINFOS (TYPE_BINFO (type))) - { - ix = TK_CLASS_TYPE; - break; - } + ix = TK_CLASS_TYPE; else { tree binfo = TYPE_BINFO (type); @@ -1327,49 +1269,13 @@ get_pseudo_ti_index (tree type) && (*base_accesses)[0] == access_public_node && !BINFO_VIRTUAL_P (base_binfo) && integer_zerop (BINFO_OFFSET (base_binfo))) - { - /* single non-virtual public. */ - ix = TK_SI_CLASS_TYPE; - break; - } + /* single non-virtual public. */ + ix = TK_SI_CLASS_TYPE; else - { - tinfo_s *ti; - tree array_domain, base_array; - - ix = TK_FIXED + num_bases; - if (vec_safe_length (tinfo_descs) <= ix) - { - /* too short, extend. */ - unsigned len = vec_safe_length (tinfo_descs); - - vec_safe_grow (tinfo_descs, ix + 1); - while (tinfo_descs->iterate (len++, &ti)) - ti->type = ti->vtable = ti->name = NULL_TREE; - } - else if ((*tinfo_descs)[ix].type) - /* already created. */ - break; - - /* Create the array of __base_class_type_info entries. */ - array_domain = build_index_type (size_int (num_bases - 1)); - base_array = build_array_type ((*tinfo_descs)[TK_BASE_TYPE].type, - array_domain); - - push_abi_namespace (); - create_pseudo_type_info - (ix, "__vmi_class_type_info", - build_decl (input_location, - FIELD_DECL, NULL_TREE, integer_type_node), - build_decl (input_location, - FIELD_DECL, NULL_TREE, integer_type_node), - build_decl (input_location, - FIELD_DECL, NULL_TREE, base_array), - NULL); - pop_abi_namespace (); - break; - } + ix = TK_VMI_CLASS_TYPES + num_bases - 1; } + break; + default: ix = TK_BUILTIN_TYPE; break; @@ -1377,107 +1283,202 @@ get_pseudo_ti_index (tree type) return ix; } -/* Make sure the required builtin types exist for generating the type_info - variable definitions. */ +/* Return pointer to tinfo descriptor. Possibly creating the tinfo + descriptor in the first place. */ -static void -create_tinfo_types (void) +static tinfo_s * +get_tinfo_desc (unsigned ix) { - tinfo_s *ti; + unsigned len = tinfo_descs->length (); - gcc_assert (!tinfo_descs); + if (len <= ix) + { + /* too short, extend. */ + len = ix + 1 - len; + vec_safe_reserve (tinfo_descs, len); + tinfo_s elt; + elt.type = elt.vtable = elt.name = NULL_TREE; + while (len--) + tinfo_descs->quick_push (elt); + } - vec_safe_grow (tinfo_descs, TK_FIXED); + tinfo_s *res = &(*tinfo_descs)[ix]; - push_abi_namespace (); + if (res->type) + return res; - /* Create the internal type_info structure. This is used as a base for - the other structures. */ - { - tree field, fields; + /* Ok, we have to create it. This layout must be consistent with + that defined in the runtime support. 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. 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. */ - field = build_decl (BUILTINS_LOCATION, - FIELD_DECL, NULL_TREE, const_ptr_type_node); - fields = field; - - field = build_decl (BUILTINS_LOCATION, - FIELD_DECL, NULL_TREE, const_string_type_node); - DECL_CHAIN (field) = fields; - fields = field; - - ti = &(*tinfo_descs)[TK_TYPE_INFO_TYPE]; - ti->type = make_class_type (RECORD_TYPE); - ti->vtable = NULL_TREE; - ti->name = NULL_TREE; - finish_builtin_struct (ti->type, "__type_info_pseudo", - fields, NULL_TREE); - } + /* Fields to add, chained in reverse order. */ + tree fields = NULL_TREE; - /* Fundamental type_info */ - create_pseudo_type_info (TK_BUILTIN_TYPE, "__fundamental_type_info", NULL); + if (ix >= TK_DERIVED_TYPES) + { + /* First field is the pseudo type_info base class. */ + tree fld_base = build_decl (BUILTINS_LOCATION, FIELD_DECL, NULL_TREE, + get_tinfo_desc (TK_TYPE_INFO_TYPE)->type); - /* Array, function and enum type_info. No additional fields. */ - create_pseudo_type_info (TK_ARRAY_TYPE, "__array_type_info", NULL); - create_pseudo_type_info (TK_FUNCTION_TYPE, "__function_type_info", NULL); - create_pseudo_type_info (TK_ENUMERAL_TYPE, "__enum_type_info", NULL); - - /* Class type_info. No additional fields. */ - create_pseudo_type_info (TK_CLASS_TYPE, "__class_type_info", NULL); - - /* Single public non-virtual base class. Add pointer to base class. - This is really a descendant of __class_type_info. */ - create_pseudo_type_info (TK_SI_CLASS_TYPE, "__si_class_type_info", - build_decl (BUILTINS_LOCATION, - FIELD_DECL, NULL_TREE, type_info_ptr_type), - NULL); + DECL_CHAIN (fld_base) = fields; + fields = fld_base; + } - /* Base class internal helper. Pointer to base type, offset to base, - flags. */ - { - tree field, fields; + switch (ix) + { + case TK_TYPE_INFO_TYPE: + { + tree fld_ptr = build_decl (BUILTINS_LOCATION, FIELD_DECL, + NULL_TREE, const_ptr_type_node); + fields = fld_ptr; + + tree fld_str = build_decl (BUILTINS_LOCATION, FIELD_DECL, + NULL_TREE, const_string_type_node); + DECL_CHAIN (fld_str) = fields; + fields = fld_str; + break; + } - field = build_decl (BUILTINS_LOCATION, - FIELD_DECL, NULL_TREE, type_info_ptr_type); - fields = field; - - field = build_decl (BUILTINS_LOCATION, - FIELD_DECL, NULL_TREE, LONGPTR_T); - DECL_CHAIN (field) = fields; - fields = field; - - ti = &(*tinfo_descs)[TK_BASE_TYPE]; - - ti->type = make_class_type (RECORD_TYPE); - ti->vtable = NULL_TREE; - ti->name = NULL_TREE; - finish_builtin_struct (ti->type, "__base_class_type_info_pseudo", - fields, NULL_TREE); - } + case TK_BASE_TYPE: + { + /* Base class internal helper. Pointer to base type, offset to + base, flags. */ + tree fld_ptr = build_decl (BUILTINS_LOCATION, FIELD_DECL, + NULL_TREE, type_info_ptr_type); + DECL_CHAIN (fld_ptr) = fields; + fields = fld_ptr; + + tree fld_flag = build_decl (BUILTINS_LOCATION, FIELD_DECL, + NULL_TREE, LONGPTR_T); + DECL_CHAIN (fld_flag) = fields; + fields = fld_flag; + break; + } + + case TK_BUILTIN_TYPE: + /* Fundamental type_info */ + break; + + case TK_ARRAY_TYPE: + break; + + case TK_FUNCTION_TYPE: + break; + + case TK_ENUMERAL_TYPE: + break; - /* Pointer type_info. Adds two fields, qualification mask - and pointer to the pointed to type. This is really a descendant of - __pbase_type_info. */ - create_pseudo_type_info (TK_POINTER_TYPE, "__pointer_type_info", - build_decl (BUILTINS_LOCATION, - FIELD_DECL, NULL_TREE, integer_type_node), - build_decl (BUILTINS_LOCATION, - FIELD_DECL, NULL_TREE, type_info_ptr_type), - NULL); - - /* Pointer to member data type_info. Add qualifications flags, - pointer to the member's type info and pointer to the class. - This is really a descendant of __pbase_type_info. */ - create_pseudo_type_info (TK_POINTER_MEMBER_TYPE, - "__pointer_to_member_type_info", - build_decl (BUILTINS_LOCATION, - FIELD_DECL, NULL_TREE, integer_type_node), - build_decl (BUILTINS_LOCATION, - FIELD_DECL, NULL_TREE, type_info_ptr_type), - build_decl (BUILTINS_LOCATION, - FIELD_DECL, NULL_TREE, type_info_ptr_type), - NULL); + case TK_POINTER_TYPE: + case TK_POINTER_MEMBER_TYPE: + { + /* Pointer type_info. Adds two fields, qualification mask and + pointer to the pointed to type. This is really a + descendant of __pbase_type_info. */ + tree fld_mask = build_decl (BUILTINS_LOCATION, FIELD_DECL, + NULL_TREE, integer_type_node); + DECL_CHAIN (fld_mask) = fields; + fields = fld_mask; + + tree fld_ptr = build_decl (BUILTINS_LOCATION, FIELD_DECL, + NULL_TREE, type_info_ptr_type); + DECL_CHAIN (fld_ptr) = fields; + fields = fld_ptr; + + if (ix == TK_POINTER_MEMBER_TYPE) + { + /* Add a pointer to the class too. */ + tree fld_cls = build_decl (BUILTINS_LOCATION, FIELD_DECL, + NULL_TREE, type_info_ptr_type); + DECL_CHAIN (fld_cls) = fields; + fields = fld_cls; + } + break; + } + + case TK_CLASS_TYPE: + /* Class type_info. No additional fields. */ + break; + + case TK_SI_CLASS_TYPE: + { + /* Single public non-virtual base class. Add pointer to base + class. This is really a descendant of + __class_type_info. */ + tree fld_ptr = build_decl (BUILTINS_LOCATION, FIELD_DECL, + NULL_TREE, type_info_ptr_type); + DECL_CHAIN (fld_ptr) = fields; + fields = fld_ptr; + break; + } + + default: /* Multiple inheritance. */ + { + unsigned num_bases = ix - TK_VMI_CLASS_TYPES + 1; + + tree fld_flg = build_decl (BUILTINS_LOCATION, FIELD_DECL, + NULL_TREE, integer_type_node); + DECL_CHAIN (fld_flg) = fields; + fields = fld_flg; + + tree fld_cnt = build_decl (BUILTINS_LOCATION, FIELD_DECL, + NULL_TREE, integer_type_node); + DECL_CHAIN (fld_cnt) = fields; + fields = fld_cnt; + + /* Create the array of __base_class_type_info entries. */ + tree domain = build_index_type (size_int (num_bases - 1)); + tree array = build_array_type (get_tinfo_desc (TK_BASE_TYPE)->type, + domain); + tree fld_ary = build_decl (BUILTINS_LOCATION, FIELD_DECL, + NULL_TREE, array); + DECL_CHAIN (fld_ary) = fields; + fields = fld_ary; + break; + } + } + + push_abi_namespace (); + + /* Generate the pseudo type name. */ + const char *real_name = tinfo_names[ix < TK_VMI_CLASS_TYPES + ? ix : unsigned (TK_VMI_CLASS_TYPES)]; + size_t name_len = strlen (real_name); + char *pseudo_name = (char *) alloca (name_len + 30); + memcpy (pseudo_name, real_name, name_len); + /* Those >= TK_VMI_CLASS_TYPES need a discriminator, may as well + apply it to all. See get_peudo_tinfo_index where we make use of + this. */ + sprintf (pseudo_name + name_len, "_pseudo_%d", ix); + + /* Create the pseudo type. */ + tree pseudo_type = make_class_type (RECORD_TYPE); + /* Pass the fields chained in reverse. */ + finish_builtin_struct (pseudo_type, pseudo_name, fields, NULL_TREE); + CLASSTYPE_AS_BASE (pseudo_type) = pseudo_type; + + res->type = cp_build_qualified_type (pseudo_type, TYPE_QUAL_CONST); + res->name = get_identifier (real_name); + + /* Pretend this is public so determine_visibility doesn't give vtables + internal linkage. */ + TREE_PUBLIC (TYPE_MAIN_DECL (res->type)) = 1; pop_abi_namespace (); + return res; +} + +/* We lazily create the type info types. */ + +static void +create_tinfo_types (void) +{ + gcc_assert (!tinfo_descs); + + vec_alloc (tinfo_descs, TK_MAX + 20); } /* Helper for emit_support_tinfos. Emits the type_info descriptor of @@ -1545,18 +1546,23 @@ emit_support_tinfos (void) 0 }; int ix; - tree bltn_type, dtor; - push_abi_namespace (); - bltn_type = xref_tag (class_type, - get_identifier ("__fundamental_type_info"), - /*tag_scope=*/ts_current, false); - pop_abi_namespace (); + /* Look for a defined class. */ + tree bltn_type = lookup_qualified_name + (abi_node, get_identifier ("__fundamental_type_info"), true, false, false); + if (TREE_CODE (bltn_type) != TYPE_DECL) + return; + + bltn_type = TREE_TYPE (bltn_type); if (!COMPLETE_TYPE_P (bltn_type)) return; - dtor = CLASSTYPE_DESTRUCTORS (bltn_type); + tree dtor = CLASSTYPE_DESTRUCTORS (bltn_type); if (!dtor || DECL_EXTERNAL (dtor)) return; + + /* All these are really builtins. So set the location. */ + location_t saved_loc = input_location; + input_location = BUILTINS_LOCATION; doing_runtime = 1; for (ix = 0; fundamentals[ix]; ix++) emit_support_tinfo_1 (*fundamentals[ix]); @@ -1568,6 +1574,7 @@ emit_support_tinfos (void) } for (tree t = registered_builtin_types; t; t = TREE_CHAIN (t)) emit_support_tinfo_1 (TREE_VALUE (t)); + input_location = saved_loc; } /* Finish a type info decl. DECL_PTR is a pointer to an unemitted @@ -1606,7 +1613,7 @@ emit_tinfo_decl (tree decl) TREE_PUBLIC (decl) = 0; DECL_EXTERNAL (decl) = 0; DECL_INTERFACE_KNOWN (decl) = 1; - } + }u import_export_decl (decl); if (DECL_NOT_REALLY_EXTERN (decl) && decl_needed_p (decl))