4.3.1.7.8.2.2. Generate nodes of type_info definition
Below it will construct these type_info type series. First is the base class.
1251 static void
1252 create_tinfo_types (void) in rtti.c
1253 {
1254 my_friendly_assert (!ti_desc_type_node, 20020609);
1255
1256 push_nested_namespace (abi_node);
If we need put a namespace in effective which is not enclosed by current namespace (for example, currently A::B, now we expect A::D), we should uses push_nested_namespace instead of push_namespace. By recursing, the function first returns back global namespace, caches content from current namespace to global namespace by push_to_top_level, then pushes content from global namespace to the expected namespace by push_namespace iteratively (refer to Enter global namespace).
3143 void
3144 push_nested_namespace (tree ns) in name-lookup.c
3145 {
3146 if (ns == global_namespace)
3147 push_to_top_level ();
3148 else
3149 {
3150 push_nested_namespace (CP_DECL_CONTEXT (ns));
3151 push_namespace (DECL_NAME (ns));
3152 }
3153 }
The reverse operation to push_nested_namespace is pop_nested_namespace. All identifiers cached are restored (refer to Return from global namespace).
3158 void
3159 pop_nested_namespace (tree ns) in name-lookup.c
3160 {
3161 timevar_push (TV_NAME_LOOKUP);
3162 while (ns != global_namespace)
3163 {
3164 pop_namespace ();
3165 ns = CP_DECL_CONTEXT (ns);
3166 }
3167
3168 pop_from_top_level ();
3169 timevar_pop (TV_NAME_LOOKUP);
3170 }
Now we are in __cxxabiv1 namespace. In directoty “gcc-3.4.6/libstdc++-v3/libsupc++”, there is head file “cxxabi.h”. This file is also found at “c++/`version`/cxxabi.h” under include directory in Linux, and the implementation is generated into library “libstdc++.so.`ver`”. The compiler is going to generate the class definitions following the file content.
In __cxxabiv1 namespace, the classes all derive from std::type_info. So it first needs create this base. But note that in below, the base is constructed within __cxxabiv1 namespace, and its name is “type_info_pseudo”. In fact, in GCC, no real std::type_info generated. In std::type_info definition below, can see that this class can’t be used alone but as base, and it has trivial destructor (though it is virtual). As those get used are derived classes in __cxxabiv1, thus it is feasible to use type_info_pseudo replacing std::type_info, as long as the methods and members used have the same declarations, and not use base pointer (compiler guarantees this). Below, it can see that type type_info_pseudo has been greatly simplified.
create_tinfo_types (continue)
1258 /* Create the internal type_info structure. This is used as a base for
1259 the other structures. */
1260 {
1261 tree field, fields;
1262
1263 ti_desc_type_node = make_aggr_type (RECORD_TYPE);
1264 field = build_decl (FIELD_DECL, NULL_TREE, const_ptr_type_node);
1265 fields = field;
1266
1267 field = build_decl (FIELD_DECL, NULL_TREE, const_string_type_node);
1268 TREE_CHAIN (field) = fields;
1269 fields = field;
1270
1271 finish_builtin_struct (ti_desc_type_node, "__type_info_pseudo",
1272 fields, NULL_TREE);
1273 TYPE_HAS_CONSTRUCTOR (ti_desc_type_node) = 1;
1274 }
Class type_info_pseudo has two anoymous data members, one is of type “const void*”, the other is “const char*”. It aims to make type_info_pseudo has the same size as std::type_info (note that std::type_info has vtable, its size equates to that of const void*). Function finish_builtin_struct finalizes the struct.
1476 void
1477 finish_builtin_struct (tree type, const char *name, tree fields, in stor-layout.c
1478 tree align_type)
1479 {
1480 tree tail, next;
1481
1482 for (tail = NULL_TREE; fields; tail = fields, fields = next)
1483 {
1484 DECL_FIELD_CONTEXT (fields) = type;
1485 next = TREE_CHAIN (fields);
1486 TREE_CHAIN (fields) = tail;
1487 }
1488 TYPE_FIELDS (type) = tail;
1489
1490 if (align_type)
1491 {
1492 TYPE_ALIGN (type) = TYPE_ALIGN (align_type);
1493 TYPE_USER_ALIGN (type) = TYPE_USER_ALIGN (align_type);
1494 }
1495
1496 layout_type (type);
1497 #if 0 /* not yet, should get fixed properly later */
1498 TYPE_NAME (type) = make_type_decl (get_identifier (name), type);
1499 #else
1500 TYPE_NAME (type) = build_decl (TYPE_DECL, get_identifier (name), type);
1501 #endif
1502 TYPE_STUB_DECL (type) = TYPE_NAME (type);
1503 layout_decl (TYPE_NAME (type), 0);
1504 }
Below is the definition of std::type_info. As comparison, type_info_pseudo doesn’t define any method, and only has unusable anonymous member. Why?
63 class type_info in typeinfo
64 {
65 public:
66 /** Destructor. Being the first non-inline virtual function, this
67 * controls in which translation unit the vtable is emitted. The
68 * compiler makes use of that information to know where to emit
69 * the runtime-mandated type_info structures in the new-abi. */
70 virtual ~type_info();
71
72 private:
73 /// Assigning type_info is not supported. Made private.
74 type_info& operator=(const type_info&);
75 type_info(const type_info&);
76
77 protected:
78 const char *__name;
79
80 protected:
81 explicit type_info(const char *__n): __name(__n) { }
82
83 public:
84 // the public interface
85 /** Returns an @e implementation-defined byte string; this is not
86 * portable between compilers! */
87 const char* name() const
88 { return __name; }
89
90 #if !__GXX_MERGED_TYPEINFO_NAMES
91 bool before(const type_info& __arg) const;
92 // In old abi, or when weak symbols are not supported, there can
93 // be multiple instances of a type_info object for one
94 // type. Uniqueness must use the _name value, not object address.
95 bool operator==(const type_info& __arg) const;
96 #else
97 /** Returns true if @c *this precedes @c __arg in the implementation's
98 * collation order. */
99 // In new abi we can rely on type_info's NTBS being unique,
100 // and therefore address comparisons are sufficient.
101 bool before(const type_info& __arg) const
102 { return __name < __arg.__name; }
103 bool operator==(const type_info& __arg) const
104 { return __name == __arg.__name; }
105 #endif
106 bool operator!=(const type_info& __arg) const
107 { return !operator==(__arg); }
108
109 // the internal interface
110 public:
111 // return true if this is a pointer type of some kind
112 virtual bool __is_pointer_p() const;
113 // return true if this is a function type
114 virtual bool __is_function_p() const;
115
116 // Try and catch a thrown type. Store an adjusted pointer to the
117 // caught type in THR_OBJ. If THR_TYPE is not a pointer type, then
118 // THR_OBJ points to the thrown object. If THR_TYPE is a pointer
119 // type, then THR_OBJ is the pointer itself. OUTER indicates the
120 // number of outer pointers, and whether they were const
121 // qualified.
122 virtual bool __do_catch(const type_info *__thr_type, void **__thr_obj,
123 unsigned __outer) const;
124
125 // internally used during catch matching
126 virtual bool __do_upcast(const __cxxabiv1::__class_type_info *__target,
127 void **__obj_ptr) const;
128 };
First, downcasting from derived pointer to base pointer needsn’t RTTI supports. The derived contains enough information, the procedure we will see later. While for upcasting from base pointer to derived pointer, in C++, there are 2 ways, one is via force-casting of C style, which won’t take any type checking; the other is by dynamic_cast operator, which is a library function accepting type_info objects as paramter. Abother place C++ will make upcasting, is the catched object in catch expression, for which the compiler will invoke dynamic_cast automatically. So as long as the front-end guarantes before handing to the back-end for emitting assemble, the arguments of dynamic_cast are real type_info objects instead the pseudo type_info objects here, it is OK (as the methods of real type_info are also in the library). Behind, can that the compiler follows this way, at the last step of the front-end processing, it replaces pseudo type_info objects with the real ones (thus, it is key for both have the same size).
Next, it is going to define pseudo type_info derived class and pseudo helper class matching those in__cxxabiv1 namespace. The criterion is also: of the same size of the real type.
create_tinfo_types (continue)
1276 /* Fundamental type_info */
1277 bltn_desc_type_node = create_pseudo_type_info
1278 ("__fundamental_type_info", 0,
1279 NULL);
1280
1281 /* Array, function and enum type_info. No additional fields. */
1282 ary_desc_type_node = create_pseudo_type_info
1283 ("__array_type_info", 0,
1284 NULL);
1285 func_desc_type_node = create_pseudo_type_info
1286 ("__function_type_info", 0,
1287 NULL);
1288 enum_desc_type_node = create_pseudo_type_info
1289 ("__enum_type_info", 0,
1290 NULL);
1291
1292 /* Class type_info. Add a flags field. */
1293 class_desc_type_node = create_pseudo_type_info
1294 ("__class_type_info", 0,
1295 NULL);
1296
1297 /* Single public non-virtual base class. Add pointer to base class.
1298 This is really a descendant of __class_type_info. */
1299 si_class_desc_type_node = create_pseudo_type_info
1300 ("__si_class_type_info", 0,
1301 build_decl (FIELD_DECL, NULL_TREE, type_info_ptr_type),
1302 NULL);
1303
1304 /* Base class internal helper. Pointer to base type, offset to base,
1305 flags. */
1306 {
1307 tree field, fields;
1308
1309 field = build_decl (FIELD_DECL, NULL_TREE, type_info_ptr_type);
1310 fields = field;
1311
1312 field = build_decl (FIELD_DECL, NULL_TREE, integer_types[itk_long]);
1313 TREE_CHAIN (field) = fields;
1314 fields = field;
1315
1316 base_desc_type_node = make_aggr_type (RECORD_TYPE);
1317 finish_builtin_struct (base_desc_type_node, "__base_class_type_info_pseudo",
1318 fields, NULL_TREE);
1319 TYPE_HAS_CONSTRUCTOR (base_desc_type_node) = 1;
1320 }
1321
1322 /* General hierarchy is created as necessary in this vector. */
1323 vmi_class_desc_type_node = make_tree_vec (10);
1324
1325 /* Pointer type_info. Adds two fields, qualification mask
1326 and pointer to the pointed to type. This is really a descendant of
1327 __pbase_type_info. */
1328 ptr_desc_type_node = create_pseudo_type_info
1329 ("__pointer_type_info", 0,
1330 build_decl (FIELD_DECL, NULL_TREE, integer_type_node),
1331 build_decl (FIELD_DECL, NULL_TREE, type_info_ptr_type),
1332 NULL);
1333
1334 /* Pointer to member data type_info. Add qualifications flags,
1335 pointer to the member's type info and pointer to the class.
1336 This is really a descendant of __pbase_type_info. */
1337 ptm_desc_type_node = create_pseudo_type_info
1338 ("__pointer_to_member_type_info", 0,
1339 build_decl (FIELD_DECL, NULL_TREE, integer_type_node),
1340 build_decl (FIELD_DECL, NULL_TREE, type_info_ptr_type),
1341 build_decl (FIELD_DECL, NULL_TREE, type_info_ptr_type),
1342 NULL);
1343
1344 pop_nested_namespace (abi_node);
1345 }
The creation of these derived classes is done by create_pseudo_type_info below. In C++, non-vritual base to derived class is the same as data member. In GCC implementation, it processes this way. Below at line 1132, the pseudo type_info is added in the derived as the base.
1112 static tree
1113 create_pseudo_type_info (const char *real_name, int ident, ...) in rtti.c
1114 {
1115 tree pseudo_type;
1116 char *pseudo_name;
1117 tree fields;
1118 tree field_decl;
1119 tree result;
1120 va_list ap;
1121
1122 va_start (ap, ident);
1123
1124 /* Generate the pseudo type name. */
1125 pseudo_name = alloca (strlen (real_name) + 30);
1126 strcpy (pseudo_name, real_name);
1127 strcat (pseudo_name, "_pseudo");
1128 if (ident)
1129 sprintf (pseudo_name + strlen (pseudo_name), "%d", ident);
1130
1131 /* First field is the pseudo type_info base class. */
1132 fields = build_decl (FIELD_DECL, NULL_TREE, ti_desc_type_node);
1133
1134 /* Now add the derived fields. */
1135 while ((field_decl = va_arg (ap, tree)))
1136 {
1137 TREE_CHAIN (field_decl) = fields;
1138 fields = field_decl;
1139 }
1140
1141 /* Create the pseudo type. */
1142 pseudo_type = make_aggr_type (RECORD_TYPE);
1143 finish_builtin_struct (pseudo_type, pseudo_name, fields, NULL_TREE);
1144 CLASSTYPE_AS_BASE (pseudo_type) = pseudo_type;
1145
1146 result = tree_cons (NULL_TREE, NULL_TREE, NULL_TREE);
1147 TINFO_REAL_NAME (result) = get_identifier (real_name);
1148 TINFO_PSEUDO_TYPE (result) =
1149 cp_build_qualified_type (pseudo_type, TYPE_QUAL_CONST);
1150
1151 va_end (ap);
1152 return result;
1153 }
Note, here parameter real_name passed in create_pseudo_type_info is the name of real type_info derived class. At line 1147, this name is set into TINFO_REAL_NAME field of the pseudo type_info derived class, which will guide the compiler to generate the object expected by dynamic_cast.
4.3.1.7.8.2.3. Using RTTI
4.3.1.7.8.2.3.1. Build RTTI for class
Only when user define class with virtual function, the compiler will generate type_info object. Or when the compiler sees dynamic_cast, it will also generate type_info object for both types. The creation is done by get_tinfo_decl. Here the parameter type is the class needs type_info object (type_info is exchangable with tinfo below).
317 tree
318 get_tinfo_decl (tree type) in class.c
319 {
320 tree name;
321 tree d;
322
323 if (COMPLETE_TYPE_P (type)
324 && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
325 {
326 error ("cannot create type information for type `%T' because its size is variable",
327 type);
328 return error_mark_node;
329 }
330
331 if (TREE_CODE (type) == METHOD_TYPE)
332 type = build_function_type (TREE_TYPE (type),
333 TREE_CHAIN (TYPE_ARG_TYPES (type)));
334
335 /* For a class type, the variable is cached in the type node
336 itself. */
337 if (CLASS_TYPE_P (type))
338 {
339 d = CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (type));
340 if (d)
341 return d;
342 }
343
344 name = mangle_typeinfo_for_type (type);
345
346 d = IDENTIFIER_GLOBAL_VALUE (name);
347 if (!d)
348 {
349 tree var_desc = get_pseudo_ti_desc (type);
350
351 d = build_lang_decl (VAR_DECL, name, TINFO_PSEUDO_TYPE (var_desc));
352
353 DECL_ARTIFICIAL (d) = 1;
354 TREE_READONLY (d) = 1;
355 TREE_STATIC (d) = 1;
356 DECL_EXTERNAL (d) = 1;
357 DECL_COMDAT (d) = 1;
358 TREE_PUBLIC (d) = 1;
359 SET_DECL_ASSEMBLER_NAME (d, name);
360
361 pushdecl_top_level_and_finish (d, NULL_TREE);
362
363 if (CLASS_TYPE_P (type))
364 CLASSTYPE_TYPEINFO_VAR (TYPE_MAIN_VARIANT (type)) = d;
365
366 /* Remember the type it is for. */
367 TREE_TYPE (name) = type;
368
369 /* Add decl to the global array of tinfo decls. */
370 my_friendly_assert (unemitted_tinfo_decls != 0, 20030312);
371 VARRAY_PUSH_TREE (unemitted_tinfo_decls, d);
372 }
373
374 return d;
375 }
At line 344, mangle_typeinfo_for_type returns the unique identifier for the tinfo of the type with mangled name (mangled name of tinfo besides follows the mangling of normal entity will have a leading “TI”). Tinfo is public static member of the class, and it uses mangled name. Thus as soon as built, it will be added into global namespace at line 361 without the risk of name collision. It greatly simplifies the searching of tinfos, code of line 346 is enough; otherwise it needs look into classes one after one with much less efficiency.
If the class hasn’t tinfo generated, it first needs get_pseudo_ti_desc to find out its type.
1159 static tree
1160 get_pseudo_ti_desc (tree type) in rtti.c
1161 {
1162 switch (TREE_CODE (type))
1163 {
1164 case OFFSET_TYPE:
1165 return ptm_desc_type_node;
1166 case POINTER_TYPE:
1167 return ptr_desc_type_node;
1168 case ENUMERAL_TYPE:
1169 return enum_desc_type_node;
1170 case FUNCTION_TYPE:
1171 return func_desc_type_node;
1172 case ARRAY_TYPE:
1173 return ary_desc_type_node;
1174 case UNION_TYPE:
1175 case RECORD_TYPE:
1176 if (TYPE_PTRMEMFUNC_P (type))
1177 return ptm_desc_type_node;
1178 else if (!COMPLETE_TYPE_P (type))
1179 {
1180 if (!at_eof)
1181 cxx_incomplete_type_error (NULL_TREE, type);
1182 return class_desc_type_node;
1183 }
1184 else if (!CLASSTYPE_N_BASECLASSES (type))
1185 return class_desc_type_node;
1186 else
1187 {
1188 tree binfo = TYPE_BINFO (type);
1189 tree base_binfos = BINFO_BASETYPES (binfo);
1190 tree base_accesses = BINFO_BASEACCESSES (binfo);
1191 tree base_binfo = TREE_VEC_ELT (base_binfos, 0);
1192 int num_bases = TREE_VEC_LENGTH (base_binfos);
1193
1194 if (num_bases == 1
1195 && TREE_VEC_ELT (base_accesses, 0) == access_public_node
1196 && !TREE_VIA_VIRTUAL (base_binfo)
1197 && integer_zerop (BINFO_OFFSET (base_binfo)))
1198 /* single non-virtual public. */
1199 return si_class_desc_type_node;
1200 else
1201 {
1202 tree var_desc;
1203 tree array_domain, base_array;
1204
1205 if (TREE_VEC_LENGTH (vmi_class_desc_type_node) <= num_bases)
1206 {
1207 int ix;
1208 tree extend = make_tree_vec (num_bases + 5);
1209
1210 for (ix = TREE_VEC_LENGTH (vmi_class_desc_type_node); ix--;)
1211 TREE_VEC_ELT (extend, ix)
1212 = TREE_VEC_ELT (vmi_class_desc_type_node, ix);
1213 vmi_class_desc_type_node = extend;
1214 }
1215 var_desc = TREE_VEC_ELT (vmi_class_desc_type_node, num_bases);
1216 if (var_desc)
1217 return var_desc;
1218
1219 /* Create the array of __base_class_type_info entries.
1220 G++ 3.2 allocated an array that had one too many
1221 entries, and then filled that extra entries with
1222 zeros. */
1223 if (abi_version_at_least (2))
1224 array_domain = build_index_type (size_int (num_bases - 1));
1225 else
1226 array_domain = build_index_type (size_int (num_bases));
1227 base_array =
1228 build_array_type (base_desc_type_node, array_domain);
1229
1230 push_nested_namespace (abi_node);
1231 var_desc = create_pseudo_type_info
1232 ("__vmi_class_type_info", num_bases,
1233 build_decl (FIELD_DECL, NULL_TREE, integer_type_node),
1234 build_decl (FIELD_DECL, NULL_TREE, integer_type_node),
1235 build_decl (FIELD_DECL, NULL_TREE, base_array),
1236 NULL);
1237 pop_nested_namespace (abi_node);
1238
1239 TREE_VEC_ELT (vmi_class_desc_type_node, num_bases) = var_desc;
1240 return var_desc;
1241 }
1242 }
1243 default:
1244 return bltn_desc_type_node;
1245 }
1246 }
vmi_class_desc_type_node originally is created as empty array of size 10 which is used for multiple-derived class. In fact this is the array of descriptors with first entry for virutal derivation, and the rest filled with __vmi_class_type_info2, __vmi_class_type_info3 and so on for derived class of variant number of bases.
In RECORD_TYPE node, VAR_DECL nodes represents static members of the class. As soon as its creation, the tinfo object can be said ready, and is added in global namespace by pushdecl_top_level_and_finish. But we have seen that the tinfo generated here is pseudo object, which needs post-processing, so it is cached into unemitted_tinfo_decls.