If valid, token follows class-head should be “{“, however when error occurs, it is no sure that token can appear. Taking a conservative approach, tokens before “}” will be abandoned with error. Otherwise, it can happily continue to parse member-specification part.
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 `}'. */
This routine attempts to parse tokens in following syntax tree.
{ 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 }
See current_access_specifier indeed records the accessibility of the members following. And the member-declaration part is handled by cp_parser_member_declaration, which forms a quite complex tree.
For our example, the first coming member is:
public:
struct Lock {
Lock() {}
Lock(const Host&) {}
};
It is a nested class definition. And being a member of host class, it will be handled by 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);
This first member complies with rule of decl-specifier-seq, which we are now parsing within (i.e, member-specifier à class-specifier à type-specifier à decl-specifier). The rule recurs! Also the rule applicable to the first member is also class-specifier. The handling procedure is quite similar, but each going his own way in pushtag as following.
5.12.3.2.1.1.3.1. Push tag for nested class
Again the node of RECORD_TYPE is created for the class.
xref_tag (continue)
9571 t = make_aggr_type (code);
9572 TYPE_CONTEXT (t) = context;
9573 pushtag (name, t, globalize);
Notice that globalize here is false, and current_binding_level returns the scope of class “SingleThreaded” which is b used here.
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);
Above name refers to identifier of “Lock”, it is a new comer, so its type slot is NULL (checked by IDENTIFIER_TYPE_VALUE). Then we can get following intermediate tree with nodes in blue fresh created for this invocation.
(Click here for open)
Figure 63: Push tag for nested class “Lock”
5.12.3.2.1.1.3.2. Create TEMPLATE_DECL for nested class
Within maybe_process_template_type_declaration, as we are still within the definition of the class template “SingleThreaded”, and processing_template_parms records the level of opened template definition (declaration) which is 1 now. It is not surprising, becaue class “Lock” is declared within the class template, it self is generic too.
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 }
What’s more, it is the nested class of the class template, in routine push_template_decl_real, primary found is zero. Also seeing that current_template_parms is unchanged till now, and same args are created from.
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 }
With similar procedure, sub-tree for template_info of the RECORD_TYPE of the nested class “Lock” is created as below figure.
(Click here for open)
Figure 64: sub-tree for TEMPLATE_DECL of class “Lock”
When returning from maybe_process_template_type_declaration, in pushtag at line 4661, PROCESSING_REAL_TEMPLATE_DECL_P returns nonzero; and as result it executes pushdecl_class_level to push the nested class within the enclosing scope, which in fact runs following code snippet.
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 }
It is worth seeing push_class_level_binding again in below. See that as within a class template, check_template_shadow faithfully checks for us if the declaration of this nested class shadows the template parameter.
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 }
Thus bindings field of the IDNETIFIER_NODE records the non-namespace enclosing scope(s), it is an important data for name look-up (this data is built by push_class_binding above). On the other hand, class_shadowed field of the enclosing class keeps track of types declared within, which is built up when push_class_binding successes. Then the intermediate tree becomes following shape.
(Click here for open)
Figure 65: Push tag for nested class “Lock” - finish
5.12.3.2.1.1.3.3. Begin nested class defintion
In exactly the same path, the nested class “Lock” invokes pushclass which push class “SingleThreaded” into current_class_stack, and then current_class_type is updated as “Lock”. And class_value field of IDENTIFIER_NODEs shadowed by “SingleThreaded” are cleaned as this field should always caches currently effective type of the name, and now it doesn’t know whether the name will be redeclared (clear_identifier_class_values). Next pushlevel_class begins the scope of “Lock”, push_class_decls at line 5504 in pushclass, the function will fill class_values of IDENTIFIER_NODEs for fields of the bases of current_class_type and the bases themselves to make them the version in the scope. Here, again this function does nothing. Now intermediate tree is shown in below.
Further by similar self reference creation proccess (refers to Build self reference), the self reference member is created as following figure.
(Click here for open)
Figure 66: Begin class definition of “Lock” – self reference