4.3.1.7.8.2.3.2. Post-processing of type_info
4.3.1.7.8.2.3.2.1. Install type_info for fundamental types
The front-end invokes function finish_file to close it work, and generate RTL code tree for the back-end. The function also constructs real objects for the pseduo type_infos cached within unemitted_tinfo_decls one by one. But before the creation, it first installs type_info for fundamental types as below.
1353 void
1354 emit_support_tinfos (void) in rtti.c
1355 {
1356 static tree *const fundamentals[] =
1357 {
1358 &void_type_node,
1359 &boolean_type_node,
1360 &wchar_type_node,
1361 &char_type_node, &signed_char_type_node, &unsigned_char_type_node,
1362 &short_integer_type_node, &short_unsigned_type_node,
1363 &integer_type_node, &unsigned_type_node,
1364 &long_integer_type_node, &long_unsigned_type_node,
1365 &long_long_integer_type_node, &long_long_unsigned_type_node,
1366 &float_type_node, &double_type_node, &long_double_type_node,
1367 0
1368 };
1369 int ix;
1370 tree bltn_type, dtor;
1371
1372 push_nested_namespace (abi_node);
1373 bltn_type = xref_tag (class_type,
1374 get_identifier ("__fundamental_type_info"),
1375 true, false);
1376 pop_nested_namespace (abi_node);
1377 if (!COMPLETE_TYPE_P (bltn_type))
1378 return;
1379 dtor = TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (bltn_type), 1);
1380 if (DECL_EXTERNAL (dtor))
1381 return;
1382 doing_runtime = 1;
1383 for (ix = 0; fundamentals[ix]; ix++)
1384 {
1385 tree bltn = *fundamentals[ix];
1386 tree bltn_ptr = build_pointer_type (bltn);
1387 tree bltn_const_ptr = build_pointer_type
1388 (build_qualified_type (bltn, TYPE_QUAL_CONST));
1389 tree tinfo;
1390
1391 tinfo = get_tinfo_decl (bltn);
1392 TREE_USED (tinfo) = 1;
1393 TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (tinfo)) = 1;
1394
1395 tinfo = get_tinfo_decl (bltn_ptr);
1396 TREE_USED (tinfo) = 1;
1397 TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (tinfo)) = 1;
1398
1399 tinfo = get_tinfo_decl (bltn_const_ptr);
1400 TREE_USED (tinfo) = 1;
1401 TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (tinfo)) = 1;
1402 }
1403 }
type_info for fundamental types, has type __fundamental_type_info, which is declared within cxxabiv1 namespace, and defined in file tinfo2.cc. If in building GCC, includes tinfo2.cc but not just cxxabi.h, then at line 1373 above, bltn_type would be a done RECORD_TYPE node, and would pass condition at line 1377 and 1380 to build type_info object for all fundamentals members. Note the objects created here are still pseduo ones. And at line 1382, doing_runtime would be set as 1 to indicate there is runtime library support.
4.3.1.7.8.2.3.2.2. Construct real type_info
In below function, parameter decl is the cached pseduo type_info.
1433 bool
1434 emit_tinfo_decl (tree decl) in rtti.c
1435 {
1436 tree type = TREE_TYPE (DECL_NAME (decl));
1437 bool non_public;
1438 int in_library = typeinfo_in_lib_p (type);
1439 tree var_desc, var_init;
1440
1441 my_friendly_assert (unemitted_tinfo_decl_p (decl), 20030307);
1442
1443 import_export_tinfo (decl, type, in_library);
1444 if (DECL_REALLY_EXTERN (decl) || !DECL_NEEDED_P (decl))
1445 return false;
1446
1447 if (!doing_runtime && in_library)
1448 return false;
1449
1450 non_public = false;
1451 var_desc = get_pseudo_ti_desc (type);
1452 var_init = get_pseudo_ti_init (type, var_desc, &non_public);
1453
1454 DECL_EXTERNAL (decl) = 0;
1455 TREE_PUBLIC (decl) = !non_public;
1456 if (non_public)
1457 DECL_COMDAT (decl) = 0;
1458
1459 DECL_INITIAL (decl) = var_init;
1460 mark_used (decl);
1461 cp_finish_decl (decl, var_init, NULL_TREE, 0);
1462 /* cp_finish_decl will have dealt with linkage. */
1463
1464 /* Say we've dealt with it. */
1465 TREE_TYPE (DECL_NAME (decl)) = NULL_TREE;
1466
1467 return true;
1468 }
Before constructing the real type_info object, the compiler needs to judge whether the object is really needed or not. Unneccessary construction not only reduces compiling efficiency, but bloats the code generated.
Below function in fact check if the type_info is for fundamental type. As these type_infos have been constructed by compiler automatically, there is no question of construct or not.
965 static bool
966 typeinfo_in_lib_p (tree type) in rtti.c
967 {
968 /* The typeinfo objects for `T*' and `const T*' are in the runtime
969 library for simple types T. */
970 if (TREE_CODE (type) == POINTER_TYPE
971 && (cp_type_quals (TREE_TYPE (type)) == TYPE_QUAL_CONST
972 || cp_type_quals (TREE_TYPE (type)) == TYPE_UNQUALIFIED))
973 type = TREE_TYPE (type);
974
975 switch (TREE_CODE (type))
976 {
977 case INTEGER_TYPE:
978 case BOOLEAN_TYPE:
979 case CHAR_TYPE:
980 case REAL_TYPE:
981 case VOID_TYPE:
982 return true;
983
984 default:
985 return false;
986 }
987 }
Function below judges if the type emitting the type_info is internal or external. If it is external, it is possible that this type_info object (note this is a global object) would be generated in other compilation unit. Then the front-end tells the back-end just to generate neccessary object. Linker can solve rest references.
1729 void
1730 import_export_tinfo (tree decl, tree type, bool is_in_library) in decl2.c
1731 {
1732 if (DECL_INTERFACE_KNOWN (decl))
1733 return;
1734
1735 if (IS_AGGR_TYPE (type))
1736 import_export_class (type);
1737
1738 if (IS_AGGR_TYPE (type) && CLASSTYPE_INTERFACE_KNOWN (type)
1739 && TYPE_POLYMORPHIC_P (type)
1740 /* If -fno-rtti, we're not necessarily emitting this stuff with
1741 the class, so go ahead and emit it now. This can happen when
1742 a class is used in exception handling. */
1743 && flag_rtti)
1744 {
1745 DECL_NOT_REALLY_EXTERN (decl) = !CLASSTYPE_INTERFACE_ONLY (type);
1746 DECL_COMDAT (decl) = 0;
1747 }
1748 else
1749 {
1750 DECL_NOT_REALLY_EXTERN (decl) = 1;
1751 DECL_COMDAT (decl) = 1;
1752 }
1753
1754 /* Now override some cases. */
1755 if (flag_weak)
1756 DECL_COMDAT (decl) = 1;
1757 else if (is_in_library)
1758 DECL_COMDAT (decl) = 0;
1759
1760 DECL_INTERFACE_KNOWN (decl) = 1;
1761 }
If the type emitting type_info is a class, then it needs below function to handle it. The function may set CLASSTYPE_INTERFACE_KNOWN for the class, which if is true, indicates we have already determined whether or not vtables, VTTs, typeinfo, and other similar per-class data should be emitted in this translation unit. For class defining virtual function, its type_info would be saved into vtable (only for this kind class, the compiler will initiatively generate type_info; otherwise, it needs triggered by dynamic_cast, and the generated tinfo is only held by dynamic_cast).
1484 static void
1485 import_export_class (tree ctype) in decl2.c
1486 {
1487 /* -1 for imported, 1 for exported. */
1488 int import_export = 0;
1489
1490 /* It only makes sense to call this function at EOF. The reason is
1491 that this function looks at whether or not the first non-inline
1492 non-abstract virtual member function has been defined in this
1493 translation unit. But, we can't possibly know that until we've
1494 seen the entire translation unit. */
1495 my_friendly_assert (at_eof, 20000226);
1496
1497 if (CLASSTYPE_INTERFACE_KNOWN (ctype))
1498 return;
1499
1500 /* If MULTIPLE_SYMBOL_SPACES is defined and we saw a #pragma interface,
1501 we will have CLASSTYPE_INTERFACE_ONLY set but not
1502 CLASSTYPE_INTERFACE_KNOWN. In that case, we don't want to use this
1503 heuristic because someone will supply a #pragma implementation
1504 elsewhere, and deducing it here would produce a conflict. */
1505 if (CLASSTYPE_INTERFACE_ONLY (ctype))
1506 return;
1507
1508 if (lookup_attribute ("dllimport", TYPE_ATTRIBUTES (ctype)))
1509 import_export = -1;
1510 else if (lookup_attribute ("dllexport", TYPE_ATTRIBUTES (ctype)))
1511 import_export = 1;
1512
1513 /* If we got -fno-implicit-templates, we import template classes that
1514 weren't explicitly instantiated. */
1515 if (import_export == 0
1516 && CLASSTYPE_IMPLICIT_INSTANTIATION (ctype)
1517 && ! flag_implicit_templates)
1518 import_export = -1;
1519
1520 /* Base our import/export status on that of the first non-inline,
1521 non-pure virtual function, if any. */
1522 if (import_export == 0
1523 && TYPE_POLYMORPHIC_P (ctype))
1524 {
1525 tree method = CLASSTYPE_KEY_METHOD (ctype);
1526 if (method)
1527 import_export = (DECL_REALLY_EXTERN (method) ? -1 : 1);
1528 }
1529
1530 #ifdef MULTIPLE_SYMBOL_SPACES
1531 if (import_export == -1)
1532 import_export = 0;
1533 #endif
1534
1535 if (import_export)
1536 {
1537 SET_CLASSTYPE_INTERFACE_KNOWN (ctype);
1538 CLASSTYPE_INTERFACE_ONLY (ctype) = (import_export < 0);
1539 }
1540 }
Above at line 1523, TYPE_POLYMORPHIC_P if nonzero, means the class has virtual function. And CLASSTYPE_KEY_METHOD at line 1525, returns the first, non-inline, non-pure-virtual function. So if we have seen the class’s definition, no doubt, vtable, typeinfo, and other similar per-class data should be emitted in this translation unit. Further, class declared with “dllexport” attribute, as explicitly declared as exported, the per-class data if needed, should be emitted here.
For common class, it has neither vtable, nor saves tinfo, the compiler tries to make the tinfo shared across translation units. So, in import_export_class at line 1751, sets DECL_COMDAT.
Back emit_tinfo_decl, at line 1444, DECL_REALLY_EXTERN has following definition:
2856 #define DECL_REALLY_EXTERN(NODE) / in cp-tree.h
2857 (DECL_EXTERNAL (NODE) && ! DECL_NOT_REALLY_EXTERN (NODE))
When tinfo is decided as external, or it is for fundamental type but runtime support is absent (condition at line 1447), then we abort the generation. Otherwise, needs going on to emit the code to initialize the real tinfo object. Note parameter var_desc of below function is the pseudo tinfo object fetched by get_pseudo_ti_desc at line 1451.
995 static tree
996 get_pseudo_ti_init (tree type, tree var_desc, bool *non_public_p) in rtti.c
997 {
998 my_friendly_assert (at_eof, 20021120);
999 switch (TREE_CODE (type))
1000 {
1001 case OFFSET_TYPE:
1002 return ptm_initializer (var_desc, type, non_public_p);
1003 case POINTER_TYPE:
1004 return ptr_initializer (var_desc, type, non_public_p);
1005 case ENUMERAL_TYPE:
1006 return generic_initializer (var_desc, type);
1007 break;
1008 case FUNCTION_TYPE:
1009 return generic_initializer (var_desc, type);
1010 break;
1011 case ARRAY_TYPE:
1012 return generic_initializer (var_desc, type);
1013 break;
1014 case UNION_TYPE:
1015 case RECORD_TYPE:
1016 if (TYPE_PTRMEMFUNC_P (type))
1017 return ptm_initializer (var_desc, type, non_public_p);
1018 else if (var_desc == class_desc_type_node)
1019 {
1020 if (!COMPLETE_TYPE_P (type))
1021 /* Emit a non-public class_type_info. */
1022 *non_public_p = true;
1023 return class_initializer (var_desc, type, NULL_TREE);
1024 }
1025 else if (var_desc == si_class_desc_type_node)
1026 {
1027 tree base_binfos = BINFO_BASETYPES (TYPE_BINFO (type));
1028 tree base_binfo = TREE_VEC_ELT (base_binfos, 0);
1029 tree tinfo = get_tinfo_ptr (BINFO_TYPE (base_binfo));
1030 tree base_inits = tree_cons (NULL_TREE, tinfo, NULL_TREE);
1031
1032 return class_initializer (var_desc, type, base_inits);
1033 }
1034 else
1035 {
1036 int hint = class_hint_flags (type);
1037 tree binfo = TYPE_BINFO (type);
1038 int nbases = BINFO_N_BASETYPES (binfo);
1039 tree base_binfos = BINFO_BASETYPES (binfo);
1040 tree base_accesses = BINFO_BASEACCESSES (binfo);
1041 tree base_inits = NULL_TREE;
1042 int ix;
1043
1044 /* Generate the base information initializer. */
1045 for (ix = nbases; ix--;)
1046 {
1047 tree base_binfo = TREE_VEC_ELT (base_binfos, ix);
1048 tree base_init = NULL_TREE;
1049 int flags = 0;
1050 tree tinfo;
1051 tree offset;
1052
1053 if (TREE_VEC_ELT (base_accesses, ix) == access_public_node)
1054 flags |= 2;
1055 tinfo = get_tinfo_ptr (BINFO_TYPE (base_binfo));
1056 if (TREE_VIA_VIRTUAL (base_binfo))
1057 {
1058 /* We store the vtable offset at which the virtual
1059 base offset can be found. */
1060 offset = BINFO_VPTR_FIELD (base_binfo);
1061 offset = convert (sizetype, offset);
1062 flags |= 1;
1063 }
1064 else
1065 offset = BINFO_OFFSET (base_binfo);
1066
1067 /* Combine offset and flags into one field. */
1068 offset = cp_build_binary_op (LSHIFT_EXPR, offset,
1069 build_int_2 (8, 0));
1070 offset = cp_build_binary_op (BIT_IOR_EXPR, offset,
1071 build_int_2 (flags, 0));
1072 base_init = tree_cons (NULL_TREE, offset, base_init);
1073 base_init = tree_cons (NULL_TREE, tinfo, base_init);
1074 base_init = build_constructor (NULL_TREE, base_init);
1075 TREE_HAS_CONSTRUCTOR (base_init) = 1;
1076 base_inits = tree_cons (NULL_TREE, base_init, base_inits);
1077 }
1078 base_inits = build_constructor (NULL_TREE, base_inits);
1079 TREE_HAS_CONSTRUCTOR (base_inits) = 1;
1080 base_inits = tree_cons (NULL_TREE, base_inits, NULL_TREE);
1081 /* Prepend the number of bases. */
1082 base_inits = tree_cons (NULL_TREE,
1083 build_int_2 (nbases, 0), base_inits);
1084 /* Prepend the hint flags. */
1085 base_inits = tree_cons (NULL_TREE,
1086 build_int_2 (hint, 0), base_inits);
1087
1088 return class_initializer (var_desc, type, base_inits);
1089 }
1090 break;
1091
1092 default:
1093 return generic_initializer (var_desc, type);
1094 }
1095 }
Using multi-derived class as example to see the creation of real tinfo, below function determines the hint flags describing the features of a class's hierarchy.
936 static int
937 class_hint_flags (tree type) in rtti.c
938 {
939 int hint_flags = 0;
940
941 dfs_walk (TYPE_BINFO (type), dfs_class_hint_mark, NULL, &hint_flags);
942 dfs_walk (TYPE_BINFO (type), dfs_class_hint_unmark, NULL, NULL);
943
944 return hint_flags;
945 }
Function dfs_walk performs depth-first post-order traversal upon the class derivation tree, whose detail we will see later. For every base of the class, dfs_class_hint_mark is performed i from most basic to most derived. See that hint is 1 for non-virtual derived class, and 3 for class containing virtual base.
899 static tree
900 dfs_class_hint_mark (tree binfo, void *data) in rtti.c
901 {
902 tree basetype = BINFO_TYPE (binfo);
903 int *hint = (int *) data;
904
905 if (TREE_VIA_VIRTUAL (binfo))
906 {
907 if (CLASSTYPE_MARKED (basetype))
908 *hint |= 1;
909 if (CLASSTYPE_MARKED2 (basetype))
910 *hint |= 2;
911 SET_CLASSTYPE_MARKED2 (basetype);
912 }
913 else
914 {
915 if (CLASSTYPE_MARKED (basetype) || CLASSTYPE_MARKED2 (basetype))
916 *hint |= 1;
917 SET_CLASSTYPE_MARKED (basetype);
918 }
919 return NULL_TREE;
920 }
The type_info object of multi-derived class has type __vmi_class_type_info. In cxxabi.h, can see that the class has an array of type __base_class_type_info to describe the bases. FOR loop at line 1045 initializes this array. And base_init is the initializers in constructing the object, see that the nodes of the list have the reverse order as members’ initialization. In addition, in the constructor of __vmi_class_type_info defined in cxxabi.h, it doesn’t initialize this __base_class_type_info array. But here, the compiler bypasses the constructor to initialize the array. Of course, the precondition is the initializers must strictly match the order of members appearance.
Class __base_class_type_info has two data members, one is pointer points to tinfo of the base, the other is a flag combining offset and information (__offset_flags). For pointer pointing to the base tinfo, its initial value is fetched by below function, it is the address of base tinfo.
380 static tree
381 get_tinfo_ptr (tree type) in rtti.c
382 {
383 tree decl = get_tinfo_decl (type);
384
385 mark_used (decl);
386 return build_nop (type_info_ptr_type,
387 build_address (decl));
388 }
For base binfo, field BINFO_OFFSET or BINFO_VPTR_FIELD (in terms of virtual base) records the offset from the derived in consideration. Thus, obviously, in __offset_flags, its high 24bits keeps this offset, and its low 8bits tells if it’s public base or virtual base. From above code, it can tell that the first data member of class __vmi_class_type_info is the flag class_hint_flags points out, the second is the number of bases, and the third is the __base_class_type_info array. As soon as the initializers ready, function class_initializer constructs node of CONSTRUCTOR to indicate the invocation of this constructor.
951 static tree
952 class_initializer (tree desc, tree target, tree trail) in rtti.c
953 {
954 tree init = tinfo_base_init (desc, target);
955
956 TREE_CHAIN (init) = trail;
957 init = build_constructor (NULL_TREE, init);
958 TREE_HAS_CONSTRUCTOR (init) = TREE_CONSTANT (init) = TREE_STATIC (init) = 1;
959 return init;
960 }
However, here, the initializers isn’t finished yet. Because tinfo of classes all are derived from __class_type_info. Under C++ standard, the base initialization should be before the data member of the derived, and for class hasing virtual function, it is also problem of initializing vtable. Types of tinfo just has virtual function. The initialization of bases must begin with the bottom one, here the bottom base type_info has a member of type “const char*”, block at line 745 constructs subtrees of its definition and initializer.
738 static tree
739 tinfo_base_init (tree desc, tree target) in rtti.c
740 {
741 tree init = NULL_TREE;
742 tree name_decl;
743 tree vtable_ptr;
744
745 {
746 tree name_name;
747
748 /* Generate the NTBS array variable. */
749 tree name_type = build_cplus_array_type
750 (build_qualified_type (char_type_node, TYPE_QUAL_CONST),
751 NULL_TREE);
752 tree name_string = tinfo_name (target);
753
754 name_name = mangle_typeinfo_string_for_type (target);
755 name_decl = build_lang_decl (VAR_DECL, name_name, name_type);
756
757 DECL_ARTIFICIAL (name_decl) = 1;
758 TREE_READONLY (name_decl) = 1;
759 TREE_STATIC (name_decl) = 1;
760 DECL_EXTERNAL (name_decl) = 0;
761 TREE_PUBLIC (name_decl) = 1;
762 import_export_tinfo (name_decl, target, typeinfo_in_lib_p (target));
763 /* External name of the string containing the type's name has a
764 special name. */
765 SET_DECL_ASSEMBLER_NAME (name_decl,
766 mangle_typeinfo_string_for_type (target));
767 DECL_INITIAL (name_decl) = name_string;
768 mark_used (name_decl);
769 pushdecl_top_level_and_finish (name_decl, name_string);
770 }
771
772 vtable_ptr = TINFO_VTABLE_DECL (desc);
773 if (!vtable_ptr)
774 {
775 tree real_type;
776
777 push_nested_namespace (abi_node);
778 real_type = xref_tag (class_type, TINFO_REAL_NAME (desc),
779 true, false);
780 pop_nested_namespace (abi_node);
781
782 if (!COMPLETE_TYPE_P (real_type))
783 {
784 /* We never saw a definition of this type, so we need to
785 tell the compiler that this is an exported class, as
786 indeed all of the __*_type_info classes are. */
787 SET_CLASSTYPE_INTERFACE_KNOWN (real_type);
788 CLASSTYPE_INTERFACE_ONLY (real_type) = 1;
789 }
790
791 vtable_ptr = get_vtable_decl (real_type, /*complete=*/1);
792 vtable_ptr = build_unary_op (ADDR_EXPR, vtable_ptr, 0);
793
794 /* We need to point into the middle of the vtable. */
795 vtable_ptr = build
796 (PLUS_EXPR, TREE_TYPE (vtable_ptr), vtable_ptr,
797 size_binop (MULT_EXPR,
798 size_int (2 * TARGET_VTABLE_DATA_ENTRY_DISTANCE),
799 TYPE_SIZE_UNIT (vtable_entry_type)));
800 TREE_CONSTANT (vtable_ptr) = 1;
801
802 TINFO_VTABLE_DECL (desc) = vtable_ptr;
803 }
804
805 init = tree_cons (NULL_TREE, vtable_ptr, init);
806
807 init = tree_cons (NULL_TREE, decay_conversion (name_decl), init);
808
809 init = build_constructor (NULL_TREE, nreverse (init));
810 TREE_HAS_CONSTRUCTOR (init) = TREE_CONSTANT (init) = TREE_STATIC (init) = 1;
811 init = tree_cons (NULL_TREE, init, NULL_TREE);
812
813 return init;
814 }
Before we have seen that pseudo tinfo hasn’t vatble. So if there is no vtable, means real tinfo object hasn’t been created. Note at line 778, TINFO_REAL_NAME saves the name of real tinfo. And the third parameter of xref_tag is true, which makes the function searching the specified type within __cxxabiv1 namespace. Constructing vtable is quite complex, we will look at it in later. Here, just know that the index of vtable doesn’t begin at 0, the compiler needs the first 2 entries for placing tinfo object, and the offset of the class being base from the derived now considering. Thus vtable_ptr points to the third entry. Further, as tinfo is static member of the class, so at line 810 sets TREE_STATIC, to tell the back-end to allocate static storage.