5.12.3.2.1.1.2. 开始类定义
跟在class-head后,应该是符号“{”,那么在下面的11890行的函数cp_parser_check_type_definition 检查定义新的类型在当前上下文是否允许(通过检查parser的type_definition_forbidden_message是否为non-null)。
cp_parser_class_specifier (continue)
11882 /* Look for the `{'. */
11883 if (!cp_parser_require (parser, CPP_OPEN_BRACE, "`{'"))
11884 {
11885 pop_deferring_access_checks ();
11886 return error_mark_node;
11887 }
11888
11889 /* Issue an error message if type-definitions are forbidden here. */
11890 cp_parser_check_type_definition (parser);
11891 /* Remember that we are defining one more class. */
11892 ++parser->num_classes_being_defined;
11893 /* Inside the class, surrounding template-parameter-lists do not
11894 apply. */
11895 saved_num_template_parameter_lists
11896 = parser->num_template_parameter_lists;
11897 parser->num_template_parameter_lists = 0;
11898
11899 /* Start the class. */
11900 if (nested_name_specifier_p)
11901 {
11902 scope = CP_DECL_CONTEXT (TYPE_MAIN_DECL (type));
11903 pop_p = push_scope (scope);
11904 }
11905 type = begin_class_definition (type);
一旦看到“{”符号,就需要为类准备上下文,并使其成为当前的上下文环境。
2011 tree
2012 begin_class_definition (tree t) in semantics.c
2013 {
2014 if (t == error_mark_node)
2015 return error_mark_node;
2016
2017 if (processing_template_parmlist)
2018 {
2019 error ("definition of `%#T' inside template parameter list", t);
2020 return error_mark_node;
2021 }
2022 /* A non-implicit typename comes from code like:
2023
2024 template <typename T> struct A {
2025 template <typename U> struct A<T>::B ...
2026
2027 This is erroneous. */
2028 else if (TREE_CODE (t) == TYPENAME_TYPE)
2029 {
2030 error ("invalid definition of qualified type `%T'", t);
2031 t = error_mark_node;
2032 }
2033
2034 if (t == error_mark_node || ! IS_AGGR_TYPE (t))
2035 {
2036 t = make_aggr_type (RECORD_TYPE);
2037 pushtag (make_anon_name (), t, 0);
2038 }
2039
2040 /* If this type was already complete, and we see another definition,
2041 that's an error. */
2042 if (COMPLETE_TYPE_P (t))
2043 {
2044 error ("redefinition of `%#T'", t);
2045 cp_error_at ("previous definition of `%#T'", t);
2046 return error_mark_node;
2047 }
2048
2049 /* Update the location of the decl. */
2050 DECL_SOURCE_LOCATION (TYPE_NAME (t)) = input_location;
2051
2052 if (TYPE_BEING_DEFINED (t))
2053 {
2054 t = make_aggr_type (TREE_CODE (t));
2055 pushtag (TYPE_IDENTIFIER (t), t, 0);
2056 }
2057 maybe_process_partial_specialization (t);
2058 pushclass (t);
上面,TYPE_BEING_DEFINED如果非0,表示我们正在定义一个类型,对于我们的例子,这个标记将在不久后被设置,但现在这个域是0。
进一步的,如果声明的不是目标的偏特化,例程maybe_process_partial_specialization不做任何事情。那么对于我们在该函数内第一件有意义的事情,是调用pushclass来建立该类的上下文。
C++中的类是可以嵌套定义的,每个类都构成了一个自己的作用域。显而易见,这些打开的类构成了一个栈。在前端中,current_class_stack就是这样的栈。它由class_stack_node_t节点构成。
50 typedef struct class_stack_node { in class.c
51 /* The name of the class. */
52 tree name;
53
54 /* The _TYPE node for the class. */
55 tree type;
56
57 /* The access specifier pending for new declarations in the scope of
58 this class. */
59 tree access;
60
61 /* If were defining TYPE, the names used in this class. */
62 splay_tree names_used;
63 }* class_stack_node_t;
那么当进入pushclass时,首先把封闭类(enclosing class)压入栈中(虽然该类现为current_class_name所指向,它实际上已经是前一个类了,当前类是正在处理的这个),而变量currnet_class_depth则记录了栈的深度。
5452 void
5453 pushclass (tree type) in class.c
5454 {
5455 type = TYPE_MAIN_VARIANT (type);
5456
5457 /* Make sure there is enough room for the new entry on the stack. */
5458 if (current_class_depth + 1 >= current_class_stack_size)
5459 {
5460 current_class_stack_size *= 2;
5461 current_class_stack
5462 = xrealloc (current_class_stack,
5463 current_class_stack_size
5464 * sizeof (struct class_stack_node));
5465 }
5466
5467 /* Insert a new entry on the class stack. */
5468 current_class_stack[current_class_depth].name = current_class_name;
5469 current_class_stack[current_class_depth].type = current_class_type;
5470 current_class_stack[current_class_depth].access = current_access_specifier;
5471 current_class_stack[current_class_depth].names_used = 0;
5472 current_class_depth++;
5473
5474 /* Now set up the new type. */
5475 current_class_name = TYPE_NAME (type);
5476 if (TREE_CODE (current_class_name) == TYPE_DECL)
5477 current_class_name = DECL_NAME (current_class_name);
5478 current_class_type = type;
5479
5480 /* By default, things in classes are private, while things in
5481 structures or unions are public. */
5482 current_access_specifier = (CLASSTYPE_DECLARED_CLASS (type)
5483 ? access_private_node
5484 : access_public_node);
5485
5486 if (previous_class_type != NULL_TREE
5487 && (type != previous_class_type
5488 || !COMPLETE_TYPE_P (previous_class_type))
5489 && current_class_depth == 1)
5490 {
5491 /* Forcibly remove any old class remnants. */
5492 invalidate_class_lookup_cache ();
5493 }
5494
5495 /* If we're about to enter a nested class, clear
5496 IDENTIFIER_CLASS_VALUE for the enclosing classes. */
5497 if (current_class_depth > 1)
5498 clear_identifier_class_values ();
当前类的信息则保存在全局变量scope_chain里,部分相关宏的定义如下。
240 #define class_binding_level scope_chain->class_bindings in cp-tree.h
727 #define current_class_name scope_chain->class_name
738 #define current_access_specifier scope_chain->access_specifier
756 #define previous_class_type scope_chain->x_previous_class_type
如果current_class_depth是1,这表示我们进入类栈顶。previous_class_type,如果我们之前访问过类栈,则指向前一个位于栈顶的这个类,这在popclass中设置。同时previous_class_value保存了previous_class_type类中的项。如果当前类与previous_class_type相同,这些缓存的数据能大大加快类上下文环境建立的速度。而如果当前类与previous_class_type不相同,就没有必要保留这些数据了。
5548 void
5549 invalidate_class_lookup_cache (void) in class.c
5550 {
5551 tree t;
5552
5553 /* The IDENTIFIER_CLASS_VALUEs are no longer valid. */
5554 for (t = previous_class_values; t; t = TREE_CHAIN (t))
5555 IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (t)) = NULL_TREE;
5556
5557 previous_class_values = NULL_TREE;
5558 previous_class_type = NULL_TREE;
5559 }
如果current_class_depth大于1,意味着我们正深入类栈,对于这个情形,class_binding_level指向封闭类(enclosing class)。域class_shadowed用作绑定在该类域中标识符的缓存,这些标识符的IDENTIFIER_CLASS_VALUE域被设置为绑定时的值。因为我们马上就要更新class_binding_level,这些IDENTIFIER_CLASS_VALUE首先要被清零。
2713 void
2714 clear_identifier_class_values (void) in name-lookup.c
2715 {
2716 tree t;
2717
2718 if (!class_binding_level)
2719 return;
2720
2721 for (t = class_binding_level->class_shadowed;
2722 t;
2723 t = TREE_CHAIN (t))
2724 IDENTIFIER_CLASS_VALUE (TREE_PURPOSE (t)) = NULL_TREE;
2725 }
随后通过pushlevel_class,我们使得当前正在定义的类的作用域成为当前作用域(即被current_binding_level及class_binding_level所指向。
pushclass (continue)
5500 pushlevel_class ();
在前端中,class_binding_level指向当前打开的最里层的类域,或者最近打开的类域(如果我们当前不在类域中)。因而我们将得到类似下图的中间树的布局,看到绑定域被创建,已准备好接收成员定义了。
2570 void
2571 pushlevel_class (void) in name-lookup.c
2572 {
2573 if (ENABLE_SCOPE_CHECKING)
2574 is_class_level = 1;
2575
2576 class_binding_level = begin_scope (sk_class, current_class_type);
2577 }
(点此打开)
图59:SingleThreaded作为当前作用域
因为对于我们的例子,previous_class_type是null,5502行的条件满足。块中的代码加入类的域,不过当前,该类还没有任何域,因此这些代码不作任何事(对于派生类,这些代码将加入代表基类的域)。
pushclass (continue)
5502 if (type != previous_class_type || current_class_depth > 1)
5503 {
5504 push_class_decls (type);
5505 if (CLASSTYPE_TEMPLATE_INFO (type) && !CLASSTYPE_USE_TEMPLATE (type))
5506 {
5507 /* If we are entering the scope of a template declaration (not a
5508 specialization), we need to push all the using decls with
5509 dependent scope too. */
5510 tree fields;
5511
5512 for (fields = TYPE_FIELDS (type);
5513 fields; fields = TREE_CHAIN (fields))
5514 if (TREE_CODE (fields) == USING_DECL && !TREE_TYPE (fields))
5515 pushdecl_class_level (fields);
5516 }
5517 }
…
5540 cxx_remember_type_decls (CLASSTYPE_NESTED_UTDS (type));
5541 }
在上面的5540行,在CLASSTYPE_NESTED_UTDS中的NESTED_UTDS表示嵌套的用户定义类型的意思。这个宏访问一个保存该类中所有嵌套的用户定义类型的绑定表。注意下面的current_binding_level返回的是cp_binding_level(也即是cxx_scope)对象,代表当前作用域。其type_decl项表示在该作用域中所声明的类型。当一个类成为当前作用域时,代表类的节点与代表作用域的节点要同步。
1542 void
1543 cxx_remember_type_decls (binding_table table) in name-lookup.c
1544 {
1545 current_binding_level->type_decls = table;
1546 }
然后,回到begin_class_definition,注意到2059行的TYPE_BEING_DEFINED,它表示类的定义尚未完整。
begin_class_definition (continue)
2059 TYPE_BEING_DEFINED (t) = 1;
2060 if (flag_pack_struct)
2061 {
2062 tree v;
2063 TYPE_PACKED (t) = 1;
2064 /* Even though the type is being defined for the first time
2065 here, there might have been a forward declaration, so there
2066 might be cv-qualified variants of T. */
2067 for (v = TYPE_NEXT_VARIANT (t); v; v = TYPE_NEXT_VARIANT (v))
2068 TYPE_PACKED (v) = 1;
2069 }
2070 /* Reset the interface data, at the earliest possible
2071 moment, as it might have been set via a class foo;
2072 before. */
2073 if (! TYPE_ANONYMOUS_P (t))
2074 {
2075 CLASSTYPE_INTERFACE_ONLY (t) = interface_only;
2076 SET_CLASSTYPE_INTERFACE_UNKNOWN_X
2077 (t, interface_unknown);
2078 }
2079 reset_specialization();
2080
2081 /* Make a declaration for this class in its own scope. */
2082 build_self_reference ();
2083
2084 return t;
2085 }