5.12.3.2.1.1.3. 解析类体
正常的话,跟在class-head后面的符号应该是“{”,不过要是发生了错误,就不能肯定该符号一定会出现。保险起见,“}”之前的符号都将丢弃,并触发错误。否则,就可以继续放心地解析member-specification部分。
cp_parser_class_specifier (continue)
11906 if (type == error_mark_node)
11907 /* If the type is erroneous, skip the entire body of the class. */
11908 cp_parser_skip_to_closing_brace (parser);
11909 else
11910 /* Parse the member-specification. */
11911 cp_parser_member_specification_opt (parser);
11912 /* Look for the trailing `}'. */
这个函数尝试按照下面的语法树解析符号。
{ member-specification [opt] }
Ⅼ access-specifier : member-specification [opt]
Ⅼ member-declaration member-specification [opt]
12392 static void
12393 cp_parser_member_specification_opt (cp_parser* parser) in parser.c
12394 {
12395 while (true)
12396 {
12397 cp_token *token;
12398 enum rid keyword;
12399
12400 /* Peek at the next token. */
12401 token = cp_lexer_peek_token (parser->lexer);
12402 /* If it's a `}', or EOF then we've seen all the members. */
12403 if (token->type == CPP_CLOSE_BRACE || token->type == CPP_EOF)
12404 break;
12405
12406 /* See if this token is a keyword. */
12407 keyword = token->keyword;
12408 switch (keyword)
12409 {
12410 case RID_PUBLIC:
12411 case RID_PROTECTED:
12412 case RID_PRIVATE:
12413 /* Consume the access-specifier. */
12414 cp_lexer_consume_token (parser->lexer);
12415 /* Remember which access-specifier is active. */
12416 current_access_specifier = token->value;
12417 /* Look for the `:'. */
12418 cp_parser_require (parser, CPP_COLON, "`:'");
12419 break;
12420
12421 default:
12422 /* Otherwise, the next construction must be a
12423 member-declaration. */
12424 cp_parser_member_declaration (parser);
12425 }
12426 }
12427 }
注意current_access_specifier确实记录了随后的成员的访问属性。而member-declaration部分由cp_parser_member_declaration来处理,这部分语法相当复杂。
至于我们的例子,第一个成员是:
public:
struct Lock {
Lock() {}
Lock(const Host&) {}
};
这是一个嵌套类定义。作为宿主类的一个成员,它将由cp_parser_member_declaration来处理。
12457 static void
12458 cp_parser_member_declaration (cp_parser* parser) in parser.c
12459 {
12460 tree decl_specifiers;
12461 tree prefix_attributes;
12462 tree decl;
12463 int declares_class_or_enum;
12464 bool friend_p;
12465 cp_token *token;
12466 int saved_pedantic;
…
12502 /* Parse the decl-specifier-seq. */
12503 decl_specifiers
12504 = cp_parser_decl_specifier_seq (parser,
12505 CP_PARSER_FLAGS_OPTIONAL,
12506 &prefix_attributes,
12507 &declares_class_or_enum);
这第一个成员依照decl-specifier-seq的规则来编译,而这正是我们当前正在解析的(即路径member-specifier à class-specifier à type-specifier à decl-specifier)。该规则递归了!同样适用于这第一个成员的规则也是class-specifier。其处理过程也相当相似,不过下面的pushtag的处理各有不同。
5.12.3.2.1.1.3.1. 加入嵌套类的标签
同样的,为该类创建了RECORD_TYPE节点。
xref_tag (continue)
9571 t = make_aggr_type (code);
9572 TYPE_CONTEXT (t) = context;
9573 pushtag (name, t, globalize);
注意到这里globalize是false,而current_binding_level返回类“SingleThreaded”的作用域,在这里是b。
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);
4618
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);
…
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);
上面name指向标识符“Lock”,这是个新标识符,因而其type域是NULL(由IDENTIFIER_TYPE_VALUE检查)。然后我们将获得如下的中间树,其中蓝色的节点是这次调用所构建的。
(点此打开)
图63:为嵌套类“Lock”加入标签
5.12.3.2.1.1.3.2. 为嵌套类创建TEMPLATE_DECL
在maybe_process_template_type_declaration中,因为我们仍然在类模板“SingleThreaded”的定义之中,并且processing_template_parms记录了打开的模板定义(声明)的层数—现在是1。因为类“Lock”是声明在类模板之中,它自己也是泛型类型。
push_tag (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 {
…
4713 }
4714 timevar_pop (TV_NAME_LOOKUP);
4715 }
更进一步的,因为是类模板中的嵌套类,在函数push_template_decl_real中,primary则是0。注意到current_template_parms直到现在还未改变,根据其创建出同样的args。
2770 tree
2771 push_template_decl_real (tree decl, int is_friend) in pt.c
2772 {
2773 tree tmpl;
2774 tree args;
2775 tree info;
2776 tree ctx;
2777 int primary;
2778 int is_partial;
2779 int new_template_p = 0;
2780
2781 /* See if this is a partial specialization. */
2782 is_partial = (DECL_IMPLICIT_TYPEDEF_P (decl)
2783 && TREE_CODE (TREE_TYPE (decl)) != ENUMERAL_TYPE
2784 && CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (decl)));
2785
2786 is_friend |= (TREE_CODE (decl) == FUNCTION_DECL && DECL_FRIEND_P (decl));
2787
2788 if (is_friend)
2789 /* For a friend, we want the context of the friend function, not
2790 the type of which it is a friend. */
2791 ctx = DECL_CONTEXT (decl);
2792 else if (CP_DECL_CONTEXT (decl)
2793 && TREE_CODE (CP_DECL_CONTEXT (decl)) != NAMESPACE_DECL)
2794 /* In the case of a virtual function, we want the class in which
2795 it is defined. */
2796 ctx = CP_DECL_CONTEXT (decl);
2797 else
2798 /* Otherwise, if we're currently defining some class, the DECL
2799 is assumed to be a member of the class. */
2800 ctx = current_scope ();
2801
2802 if (ctx && TREE_CODE (ctx) == NAMESPACE_DECL)
2803 ctx = NULL_TREE;
2804
2805 if (!DECL_CONTEXT (decl))
2806 DECL_CONTEXT (decl) = FROB_CONTEXT (current_namespace);
2807
2808 /* See if this is a primary template. */
2809 primary = template_parm_scope_p ();
2810
2811 if (primary)
2812 {
…
2852 }
2853
2854 /* Check to see that the rules regarding the use of default
2855 arguments are not being violated. */
2856 check_default_tmpl_args (decl, current_template_parms,
2857 primary, is_partial);
2858
2859 if (is_partial)
2860 return process_partial_specialization (decl);
2861
2862 args = current_template_args ();
2863
2864 if (!ctx
2865 || TREE_CODE (ctx) == FUNCTION_DECL
2866 || (CLASS_TYPE_P (ctx) && TYPE_BEING_DEFINED (ctx))
2867 || (is_friend && !DECL_TEMPLATE_INFO (decl)))
2868 {
2869 if (DECL_LANG_SPECIFIC (decl)
2870 && DECL_TEMPLATE_INFO (decl)
2871 && DECL_TI_TEMPLATE (decl))
2872 tmpl = DECL_TI_TEMPLATE (decl);
2873 /* If DECL is a TYPE_DECL for a class-template, then there won't
2874 be DECL_LANG_SPECIFIC. The information equivalent to
2875 DECL_TEMPLATE_INFO is found in TYPE_TEMPLATE_INFO instead. */
2876 else if (DECL_IMPLICIT_TYPEDEF_P (decl)
2877 && TYPE_TEMPLATE_INFO (TREE_TYPE (decl))
2878 && TYPE_TI_TEMPLATE (TREE_TYPE (decl)))
2879 {
…
2888 }
2889 else
2890 {
2891 tmpl = build_template_decl (decl, current_template_parms);
2892 new_template_p = 1;
2893
2894 if (DECL_LANG_SPECIFIC (decl)
2895 && DECL_TEMPLATE_SPECIALIZATION (decl))
2896 {
…
2902 }
2903 }
2904 }
…
2997 DECL_TEMPLATE_RESULT (tmpl) = decl;
2998 TREE_TYPE (tmpl) = TREE_TYPE (decl);
…
3031 info = tree_cons (tmpl, args, NULL_TREE);
3032
3033 if (DECL_IMPLICIT_TYPEDEF_P (decl))
3034 {
3035 SET_TYPE_TEMPLATE_INFO (TREE_TYPE (tmpl), info);
3036 if ((!ctx || TREE_CODE (ctx) != FUNCTION_DECL)
3037 && TREE_CODE (TREE_TYPE (decl)) != ENUMERAL_TYPE
3038 /* Don't change the name if we've already set it up. */
3039 && !IDENTIFIER_TEMPLATE (DECL_NAME (decl)))
3040 DECL_NAME (decl) = classtype_mangled_name (TREE_TYPE (decl));
3041 }
3042 else if (DECL_LANG_SPECIFIC (decl))
3043 DECL_TEMPLATE_INFO (decl) = info;
3044
3045 return DECL_TEMPLATE_RESULT (tmpl);
3046 }
经过相似的过程,嵌套类“Lock”的RECORD_TYPE的template_info处的所被创建的子树如下图中红色节点。
(点此打开)
图64:类“Lock”的TEMPLATE_DECL子树
当从maybe_process_template_type_declaration返回时,在pushtag的4661行,PROCESSING_REAL_TEMPLATE_DECL_P返回非0,因而执行pushdecl_class_level,在封闭类中加入嵌套类,实际执行的是以下的代码片段。
pushdecl_class_level
2740 name = DECL_NAME (x);
2741
2742 if (name)
2743 {
2744 is_valid = push_class_level_binding (name, x);
2745 if (TREE_CODE (x) == TYPE_DECL)
2746 set_identifier_type_value (name, x);
2747 }
下面重新列出push_class_level_binding。在一个类模板里面, check_template_shadow仍然称职地检查该嵌套类的定义是否会屏蔽模板参数。
2772 bool
2773 push_class_level_binding (tree name, tree x) in namespace-lookup.c
2774 {
…
2783 /* Make sure that this new member does not have the same name
2784 as a template parameter. */
2785 if (TYPE_BEING_DEFINED (current_class_type))
2786 check_template_shadow (x);
…
2824 /* If this declaration shadows a declaration from an enclosing
2825 class, then we will need to restore IDENTIFIER_CLASS_VALUE when
2826 we leave this class. Record the shadowed declaration here. */
2827 binding = IDENTIFIER_BINDING (name);
…
2880 /* If we didn't replace an existing binding, put the binding on the
2881 stack of bindings for the identifier, and update the shadowed list. */
2882 if (push_class_binding (name, x))
2883 {
2884 class_binding_level->class_shadowed
2885 = tree_cons (name, NULL,
2886 class_binding_level->class_shadowed);
2887 /* Record the value we are binding NAME to so that we can know
2888 what to pop later. */
2889 TREE_TYPE (class_binding_level->class_shadowed) = x;
2890 POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, true);
2891 }
2892
2893 POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, false);
2894 }
那么其IDNETIFIER_NODE的bindings域记录了其所在的非名字空间作用域,这是名字查找时,非常重要的数据结构(该数据由上面的push_class_binding构建)。另一方面, 封闭类的class_shadowed域则记录了其中所声明的类型,当push_class_binding成功,就为之构建。那么现在中间树看起来如下。
(点此打开)
图65:为嵌套类“Lock”加入标签—完成
5.12.3.2.1.1.3.3. 开始嵌套类定义
通过同样的路径,嵌套类“Lock”调用pushclass,在这其中把类“SingleThreaded”加入current_class_stack,而后current_class_type被更新为“Lock”。而被“SingleThreaded”掩蔽的IDENTIFIER_NODE节点的class_value域都被清零,因为这个域应该总是保存该名字当前的类型,而现在不知道这个名字是否会被重新声明(clear_identifier_class_values)。接着pushlevel_class开始了“Lock”的作用域。在pushclass 5504行的push_class_decls,该函数将填充的current_class_type基类,以及其域的IDENTIFIER_NODE节点的class_values域,使其成为当前作用域中使用得的类型。在这里,这个函数也是不作任何事情。
进一步的,通过类似的对自己引用的构建过程(参考构建对自己的引用),中间树看起来就像下面。
(点此打开)
图66:开始“Lock”的类定义—对自己的引用