4.3.1.7.8.2.2. 构建type_info的定义
下面就是构建这个type_info类型系列。首先是基类。
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);
如果我们需要将不是被当前名字空间所包含的名字空间,作为当前名字空间(例如,当前是A::B,现在我们需要A::D),那么我们应该使用push_nested_namespace,而不是push_namespace。这个函数通过递归,首先回溯到全局名字空间,由push_to_top_level将当前名字空间到全局名字空间之间的内容缓存,然后由push_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 }
push_nested_namespace的反向操作是pop_nested_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 }
现在我们在名字空间__cxxabiv1里了。在“gcc-3.4.6/libstdc++-v3/libsupc++”目录下,GCC有文件cxxabi.h。这个文件就是Linux系统include目录中的“c++/`version`/cxxabi.h”,而其代码生成在libstdc++.so.`ver`库文件里。编译器将按这个文件的内容来生成类定义。
__cxxabiv1名字空间里的类定义都是std::type_info的派生类。因此,首先应该构建这个基类。但是注意下面,这个基类构建在__cxxabiv1名字空间里,且名字是“type_info_pseduo”。事实上,在GCC内部并没有生成std::type_info的定义。在下面std::type_info的定义中,我们可以看到这个类不能单独使用,只能作为基类,而且它具有平凡析构函数(虽然是虚函数)。真正被使用的是__cxxabiv1中的type_info派生类。那么我们偷梁换柱,用type_info_pseduo来替换std::type_info亦无不可,只要我们用到方法、成员都一样的声明,并且不使用基类指针(编译器保证这一点)。下面可以看到type_info_pseduo类是被大大简化了的。
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 }
类type_info_pseduo具有2个匿名成员,一个具有类型“const void*”,另一个是类型“const char*”。这是为了让type_info_pseduo与std::type_info具有相同的大小(注意std::type_info有虚函数表,其大小就是const void*)。函数finish_builtin_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 }
下面将std::type_info的定义列出。作为对比,type_info_pseduo没有定义任何方法,而且只有不可用的匿名成员。为什么会这样呢?
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