下面的 abort_fndecl 代表函数 abort ,而函数 build_library_fn_ptr 与 build_library_fn 相仿,不过它接受字符串作为名字,而不是标识符节点。
cxx_init_decl_processing (continue)
3115 abort_fndecl
3116 = build_library_fn_ptr ("__cxa_pure_virtual", void_ftype);
3117
3118 /* Perform other language dependent initializations. */
3119 init_class_processing ();
3120 init_search_processing ();
3121 init_rtti_processing ();
3122
3123 if (flag_exceptions )
3124 init_exception_processing ();
3125
3126 if (! supports_one_only ())
3127 flag_weak = 0;
3128
3129 make_fname_decl = cp_make_fname_decl;
3130 start_fname_decls ();
3131
3132 /* Show we use EH for cleanups. */
3133 using_eh_for_cleanups ();
3134
3135 /* Maintain consistency. Perhaps we should just complain if they
3136 say -fwritable-strings? */
3137 if (flag_writable_strings )
3138 flag_const_strings = 0;
3139 }
在处理类声明时, GCC 使用以下的全局变量来控制其处理过程。其中 current_class_depth 表示当前类的嵌套深度,这些嵌套的类毫无疑问构成了一个栈,这就是 current_class_stack ,而 current_class_stack_size 就是栈的当前大小。 GNU C++ 有一个扩展,允许在函数体中定义类,当然这个类只能在该函数体内可见,为了与其他类区别,它们被保存在 local_classes 中。
5424 void
5425 init_class_processing (void) in class.c
5426 {
5427 current_class_depth = 0;
5428 current_class_stack_size = 10;
5429 current_class_stack
5430 = xmalloc (current_class_stack_size * sizeof (struct class_stack_node));
5431 VARRAY_TREE_INIT (local_classes , 8, "local_classes");
5432
5433 ridpointers [(int) RID_PUBLIC] = access_public_node;
5434 ridpointers [(int) RID_PRIVATE] = access_private_node;
5435 ridpointers [(int) RID_PROTECTED] = access_protected_node;
5436 }
而下面所初始化的 search_obstack 在当前版本中已没有用处,在 V4 版本中已被去除。
2346 void
2347 init_search_processing (void) in search.c
2348 {
2349 gcc_obstack_init (&search_obstack );
2350 }
4.3.1.7.8.2.1. 构建 TYPE_DECL 节点
运行时类型识别( runtime type identification , RTTI )允许操纵基类的指针或引用对象,来获取该指针或引用对象的实际派生类型。为了支持 RTTI , GCC 提供了 2 个操作符: typeid 和 dynamic_cast 。 typeid 的返回类型是 type_info ,而 type_info 的定义是依赖于实现的。在这里对 RTTI 的初始化中,不像 std::bad_alloc ,必须创建完整的定义,因为这个类是运行时环境所需要使用的。
115 void
116 init_rtti_processing (void) in rtti.c
117 {
118 tree const_type_info_type;
119
120 push_namespace (std_identifier);
121 type_info_type_node
122 = xref_tag (class_type, get_identifier ("type_info"),
123 true, false);
124 pop_namespace ();
125 const_type_info_type = build_qualified_type (type_info_type_node,
126 TYPE_QUAL_CONST);
127 type_info_ptr_type = build_pointer_type (const_type_info_type);
128 type_info_ref_type = build_reference_type (const_type_info_type);
129
130 VARRAY_TREE_INIT (unemitted_tinfo_decls , 10, "RTTI decls");
131
132 create_tinfo_types ();
133 }
这儿 xref_tag 尝试获取具有 name 名字的 struct , enum 或 union ( tag_code 告知是哪个)。如果该类型还没定义,把标签( tag )定义为前向引用。
如果参数 globalize 是 false ,表示标识符 name 是一个定义。在 C++ 中,首先,它允许在不同绑定域(即作用域)中定义同名的类型;其次,在同一绑定域中,同名的不同类型是一个语法错误,除非它们的定义是相同的。在 9476 行, lookup_tag 尝试,在由 b 提交的绑定域中,找出由 code 和 name 指定的类型定义。我们在后面来看这个函数的定义。
而如果 globalize 是 true ,则 name 只是一个类型声明。在 C++ 中,我们可以仅声明一个用户定义类型,然后使用其指针(只要不解引用)。例如,
class A;
A* pa = NULL;
在 GCC 内部,当它发现找不到任何东西时,它将创建一个伪类型(记得 std::bad_alloc ?),然后为它声明一个隐式的 typedef ,并且将由这个隐式 typedef 所构建的 TYPE_DECL 节点加入指定的绑定域。那么前向声明实际上就是引用这个 TYPE_DECL ,随后当遇到真正的定义时,对应的类型节点(类型 RECORD_TYPE ,或 UNION_TYPE ,或 ENUMERAL_TYPE )进行相应地更新。而当 GCC 找到存在的类型声明(不是伪类型),而且该声明与泛型编程相关,则需要特殊的处理,我们不久将看到这一点。
9443 tree
9444 xref_tag (enum tag_types tag_code, tree name, in decl.c
9445 bool globalize, bool template_header_p)
9446 {
9447 enum tree_code code;
9448 tree t;
9449 struct cp_binding_level *b = current_binding_level;
9450 tree context = NULL_TREE;
9451
9452 timevar_push (TV_NAME_LOOKUP);
9453
9454 my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 0);
9455
9456 switch (tag_code)
9457 {
9458 case record_type:
9459 case class_type:
9460 code = RECORD_TYPE;
9461 break ;
9462 case union_type:
9463 code = UNION_TYPE;
9464 break ;
9465 case enum_type:
9466 code = ENUMERAL_TYPE;
9467 break ;
9468 default :
9469 abort ();
9470 }
9471
9472 if (! globalize)
9473 {
9474 /* If we know we are defining this tag, only look it up in
9475 this scope and don't try to find it as a type. */
9476 t = lookup_tag (code, name, b, 1);
9477 }
9478 else
9479 {
9480 tree decl = lookup_name (name, 2);
这里 globalize 是 true ,使用 lookup_name 来类型声明,因为其第二个参数表示抛弃非类型声明。 lookup_name 是一个复杂的函数,为了不使这里的过程太漫长,我们暂时跳过它。对于我们这里的情形, lookup_name 应该返回 NULL ,因为这必须是第一次声明这个类型。
xref_tag (continue)
9558 if (! t)
9559 {
9560 /* If no such tag is yet defined, create a forward-reference node
9561 and record it as the "definition".
9562 When a real declaration of this type is found,
9563 the forward-reference will be altered into a real type. */
9564 if (code == ENUMERAL_TYPE)
9565 {
9566 error ("use of enum `%#D' without previous declaration", name);
9567 POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, error_mark_node);
9568 }
9569 else
9570 {
9571 t = make_aggr_type (code);
9572 TYPE_CONTEXT (t) = context;
9573 pushtag (name, t, globalize);
9574 }
9575 }
9576 else
9577 {
...
9587 }
9588
9589 POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, t);
9590 }
因为在 9480 行,没有标签( tag )被 lookup_name 所找出,那么将为之创建一个节点。并且由于参数 tag_code 是 class_type ,这个节点应该是 RECORD_TYPE ,而且它的上下文首先被设置为空(参见 9450 行的 NULL_TREE )。
4589 void
4590 pushtag (tree name, tree type, int globalize) in name-lookup.c
4591 {
4592 struct cp_binding_level *b;
4593
4594 timevar_push (TV_NAME_LOOKUP);
4595 b = current_binding_level ;
4596 while (/* Cleanup scopes are not scopes from the point of view of
4597 the language. */
4598 b->kind == sk_cleanup
4599 /* Neither are the scopes used to hold template parameters
4600 for an explicit specialization. For an ordinary template
4601 declaration, these scopes are not scopes from the point of
4602 view of the language -- but we need a place to stash
4603 things that will go in the containing namespace when the
4604 template is instantiated. */
4605 || (b->kind == sk_template_parms && b->explicit_spec_p)
4606 || (b->kind == sk_class
4607 && (globalize
4608 /* We may be defining a new type in the initializer
4609 of a static member variable. We allow this when
4610 not pedantic, and it is particularly useful for
4611 type punning via an anonymous union. */
4612 || COMPLETE_TYPE_P (b->this_entity))))
4613 b = b->level_chain;
4614
4615 if (b->type_decls == NULL)
4616 b->type_decls = binding_table_new (SCOPE_DEFAULT_HT_SIZE);
4617 binding_table_insert (b->type_decls, name, type);
pushtag 首先把类型定义加入当前名字空间。我们已经看到,在一个绑定域中的用户定义类型,被保存在相应的 cp_binding_level 结构的 type_decls 域中。下面的 binding_table_insert 提供了这个处理。
190 static void
191 binding_table_insert (binding_table table, tree name, tree type) in name-lookup.c
192 {
193 const unsigned int hash = IDENTIFIER_HASH_VALUE (name);
194 const size_t i = ENTRY_INDEX (hash, table->chain_count);
195 binding_entry entry = binding_entry_make (name, type);
196
197 entry->chain = table->chain[i];
198 table->chain[i] = entry;
199 ++table->entry_count;
200
201 if (3 * table->chain_count < 5 * table->entry_count)
202 binding_table_expand (table);
203 }
注意到 type_decls 实际上是一个哈希表,所有具有同一哈希值的类型定义被链接在一起。为了控制链表的长度,如果链表的数目(域 chain_count )与表项数( entry_count )具有如下关系时: 3*table->chain_count < 5*table->entry_count , binding_table_expand 将链表数目加倍,并重新哈希及链接已记录的类型。
67 static inline binding_entry
68 binding_entry_make (tree name, tree type) in name-lookup.c
69 {
70 binding_entry entry;
71
72 if (free_binding_entry )
73 {
74 entry = free_binding_entry ;
75 free_binding_entry = entry->chain;
76 }
77 else
78 entry = ggc_alloc (sizeof (struct binding_entry_s));
79
80 entry->name = name;
81 entry->type = type;
82 entry->chain = NULL;
83
84 return entry;
85 }
在上面是 binding_entry_make 中,虽然标识符与类型定义通过 binding_entry 实例关联起来了,但标识符节点还没有与 TYPE_DECL 节点绑定。因此在下面, IDENTIFIER_TYPE_VALUE 返回 NULL 。
1700 tree
1701 identifier_type_value (tree id) in name-lookup.c
1702 {
1703 timevar_push (TV_NAME_LOOKUP);
1704 /* There is no type with that name, anywhere. */
1705 if (REAL_IDENTIFIER_TYPE_VALUE (id) == NULL_TREE)
1706 POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, NULL_TREE);
1707 /* This is not the type marker, but the real thing. */
1708 if (REAL_IDENTIFIER_TYPE_VALUE (id) != global_type_node )
1709 POP_TIMEVAR_AND_RETURN(TV_NAME_LOOKUP, REAL_IDENTIFIER_TYPE_VALUE (id));
1710 /* Have to search for it. It must be on the global level, now.
1711 Ask lookup_name not to return non-types. */
1712 id = lookup_name_real (id, 2, 1, 0, LOOKUP_COMPLAIN);
1713 if (id)
1714 POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, TREE_TYPE (id));
1715 POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, NULL_TREE);
1716 }
IDENTIFIER_TYPE_VALUE 只是 identifier_type_value 的一个直接的封装。在这里,在我们的情形下, REAL_IDENTIFIER_TYPE_VALUE 应该返回 NULL_TREE ,而下面 4622 行的 type 则是刚创建的 RECORD_TYPE 节点。
pushtag (continue)
4619 if (name)
4620 {
4621 /* Do C++ gratuitous typedefing. */
4622 if (IDENTIFIER_TYPE_VALUE (name) != type)
4623 {
4624 tree d = NULL_TREE;
4625 int in_class = 0;
4626 tree context = TYPE_CONTEXT (type);
4627
4628 if (! context)
4629 {
4630 tree cs = current_scope ();
4631
4632 if (! globalize)
4633 context = cs;
4634 else if (cs != NULL_TREE && TYPE_P (cs))
4635 /* When declaring a friend class of a local class, we want
4636 to inject the newly named class into the scope
4637 containing the local class, not the namespace scope. */
4638 context = decl_function_context (get_type_decl (cs));
4639 }
4640 if (!context)
4641 context = current_namespace ;
4642
4643 if (b->kind == sk_class
4644 || (b->kind == sk_template_parms
4645 && b->level_chain->kind == sk_class))
4646 in_class = 1;
4647
4648 if (current_lang_name == lang_name_java)
4649 TYPE_FOR_JAVA (type) = 1;
4650
4651 d = create_implicit_typedef (name, type);
4652 DECL_CONTEXT (d) = FROB_CONTEXT (context);
4653 if (! in_class)
4654 set_identifier_type_value_with_scope (name, d, b);
回忆这个类型的上下文是 NULL ,因而在 4630 行, current_scope 被调用。这是一个宏,视情况在 current_function_decl 和 current_class_type 中选择,对于名字空间作用域,它永远返回 NULL 。那么因为我们在 std 名字空间中,在 4641 行,类型上下文被设为当前名字空间作用域。
接着在 4651 行,由 create_implicit_typedef 为类型构建了一个 TYPE_DECL 节点。然后在 set_identifier_type_value_with_scope 里,这个 TYPE_DECL 节点(注意不是类型定义)将被记录入标识符节点的 namespace_bindings 域中。
1731 static void
1732 set_identifier_type_value_with_scope (tree id, tree decl, cxx_scope *b) in name-lookup.c
1733 {
1734 tree type;
1735
1736 if (b->kind != sk_namespace)
1737 {
1738 /* Shadow the marker, not the real thing, so that the marker
1739 gets restored later. */
1740 tree old_type_value = REAL_IDENTIFIER_TYPE_VALUE (id);
1741 b->type_shadowed
1742 = tree_cons (id, old_type_value, b->type_shadowed);
1743 type = decl ? TREE_TYPE (decl) : NULL_TREE;
1744 }
1745 else
1746 {
1747 cxx_binding *binding =
1748 binding_for_name (NAMESPACE_LEVEL (current_namespace), id);
1749 if (decl)
1750 {
1751 if (binding->value)
1752 supplement_binding (binding, decl);
1753 else
1754 binding->value = decl;
1755 }
1756 else
1757 abort ();
1758 /* Store marker instead of real type. */
1759 type = global_type_node ;
1760 }
1761 SET_IDENTIFIER_TYPE_VALUE (id, type);
1762 }
在上面 1754 行的赋值操作设置了该标识符目前对应的声明(这是个类型声明)。自此,在当前作用域,该标识符就表示该类型。
pushtag (continue)
4656 d = maybe_process_template_type_declaration (type,
4657 globalize, b);
4658
4659 if (b->kind == sk_class)
4660 {
4661 if (!PROCESSING_REAL_TEMPLATE_DECL_P ())
4662 /* Put this TYPE_DECL on the TYPE_FIELDS list for the
4663 class. But if it's a member template class, we
4664 want the TEMPLATE_DECL, not the TYPE_DECL, so this
4665 is done later. */
4666 finish_member_declaration (d);
4667 else
4668 pushdecl_class_level (d);
4669 }
4670 else
4671 d = pushdecl_with_scope (d, b);
4672
4673 /* FIXME what if it gets a name from typedef? */
4674 if (ANON_AGGRNAME_P (name))
4675 DECL_IGNORED_P (d) = 1;
4676
4677 TYPE_CONTEXT (type) = DECL_CONTEXT (d);
4678
4679 /* If this is a local class, keep track of it. We need this
4680 information for name-mangling, and so that it is possible to find
4681 all function definitions in a translation unit in a convenient
4682 way. (It's otherwise tricky to find a member function definition
4683 it's only pointed to from within a local class.) */
4684 if (TYPE_CONTEXT (type)
4685 && TREE_CODE (TYPE_CONTEXT (type)) == FUNCTION_DECL
4686 && !processing_template_decl)
4687 VARRAY_PUSH_TREE (local_classes , type);
4688 }
4689 if (b->kind == sk_class
4690 && !COMPLETE_TYPE_P (current_class_type ))
4691 {
4692 maybe_add_class_template_decl_list (current_class_type ,
4693 type, /*friend_p=*/ 0);
4694 CLASSTYPE_NESTED_UTDS (current_class_type ) = b->type_decls;
4695 }
4696 }
4697
4698 if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL)
4699 /* Use the canonical TYPE_DECL for this node. */
4700 TYPE_STUB_DECL (type) = TYPE_NAME (type);
4701 else
4702 {
4703 /* Create a fake NULL-named TYPE_DECL node whose TREE_TYPE
4704 will be the tagged type we just added to the current
4705 binding level. This fake NULL-named TYPE_DECL node helps
4706 dwarfout.c to know when it needs to output a
4707 representation of a tagged type, and it also gives us a
4708 convenient place to record the "scope start" address for
4709 the tagged type. */
4710
4711 tree d = build_decl (TYPE_DECL, NULL_TREE, type);
4712 TYPE_STUB_DECL (type) = pushdecl_with_scope (d, b);
4713 }
4714 timevar_pop (TV_NAME_LOOKUP);
4715 }
现在我们已经把类型定义( RECORD_TYPE 节点)加入到了绑定域中,还把对应的 TYPE_DECL 节点加入到标识符节点的绑定链里。下面的 1960 行, pushdecl 只是调用 add_decl_to_level 把 TYPE_DECL 节点加入对应 cxx_scope 的 names 域。
1941 tree
1942 pushdecl_with_scope (tree x, cxx_scope *level) in name-lookup.c
1943 {
1944 struct cp_binding_level *b;
1945 tree function_decl = current_function_decl ;
1946
1947 timevar_push (TV_NAME_LOOKUP);
1948 current_function_decl = NULL_TREE;
1949 if (level->kind == sk_class)
1950 {
1951 b = class_binding_level;
1952 class_binding_level = level;
1953 pushdecl_class_level (x);
1954 class_binding_level = b;
1955 }
1956 else
1957 {
1958 b = current_binding_level ;
1959 current_binding_level = level;
1960 x = pushdecl (x);
1961 current_binding_level = b;
1962 }
1963 current_function_decl = function_decl;
1964 POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, x);
1965 }
type_info 实际上是一个类型系列,编译器根据类的结构选择其一,结构相同的类所选用的 type_info 是一样的,但是不同的实例。因此,编译器在遇到使用 type_info 的地方,并不急着构建实例,而是在前端最后完成这个编译单元时,集中地构建。这些 type_info 所需要的缓存就是在 init_rtti_processing 的 130 行的 unemitted_tinfo_decls 。