Class-specifier follows the rule: class-specifier: class-head { member-specification [opt] }
11855 static tree
11856 cp_parser_class_specifier (cp_parser* parser) in parser.c
11857 {
11858 cp_token *token;
11859 tree type;
11860 tree attributes;
11861 int has_trailing_semicolon;
11862 bool nested_name_specifier_p;
11863 unsigned saved_num_template_parameter_lists;
11864 bool pop_p = false;
11865 tree scope = NULL_TREE;
11866
11867 push_deferring_access_checks (dk_no_deferred);
11868
11869 /* Parse the class-head. */
11870 type = cp_parser_class_head (parser,
11871 &nested_name_specifier_p,
11872 &attributes);
11873 /* If the class-head was a semantic disaster, skip the entire body
11874 of the class. */
11875 if (!type)
11876 {
11877 cp_parser_skip_to_end_of_block_or_statement (parser);
11878 pop_deferring_access_checks ();
11879 return error_mark_node;
11880 }
Above at line 11867, prepares deferred access control checking for this class-specifier. As the type is dk_no_deferred, so at poping out of the stack, the checkings will be done immediately.
5.12.3.2.1.1.1. Parse class-head
class-head describes the inheritance hierachy between classes by base-clause entity, besides nested-name-specifier entity describes the binding scope the class will be defined.
class-head
├ class-key identifier [opt] base-clause [opt]
├ class-key nested-name-specifier [opt] base-clause [opt]
├ class-key nested-name-specifier [opt] template-id base-clause [opt]
GNU Ext ├ class-key attributes identifer [opt] base-clause [opt]
GNU Ext ├ class-key attributes nested-name-specifier [opt] base-clause [opt]
GNU Ext Ⅼ class-key attributes nested-name-specifier [opt] template-id base-clause [opt]
├ class
├ struct
Ⅼ union
So in the handling function, parameter nested_name_specifier_p is set to true if and only if one of the productions involving a nested-name-specifier was used, and false otherwise. Here for the second statement in our example contains class-head of “class SingleThreaded”.
12030 static tree
12031 cp_parser_class_head (cp_parser* parser, in parser.c
12032 bool* nested_name_specifier_p,
12033 tree *attributes_p)
12034 {
12035 cp_token *token;
12036 tree nested_name_specifier;
12037 enum tag_types class_key;
12038 tree id = NULL_TREE;
12039 tree type = NULL_TREE;
12040 tree attributes;
12041 bool template_id_p = false;
12042 bool qualified_p = false;
12043 bool invalid_nested_name_p = false;
12044 bool invalid_explicit_specialization_p = false;
12045 bool pop_p = false;
12046 unsigned num_templates;
12047
12048 /* Assume no nested-name-specifier will be present. */
12049 *nested_name_specifier_p = false;
12050 /* Assume no template parameter lists will be used in defining the
12051 type. */
12052 num_templates = 0;
12053
12054 /* Look for the class-key. */
12055 class_key = cp_parser_class_key (parser);
12056 if (class_key == none_type)
12057 return error_mark_node;
12058
12059 /* Parse the attributes. */
12060 attributes = cp_parser_attributes_opt (parser);
12061
12062 /* If the next token is `::', that is invalid -- but sometimes
12063 people do try to write:
12064
12065 struct ::S {};
12066
12067 Handle this gracefully by accepting the extra qualifier, and then
12068 issuing an error about it later if this really is a
12069 class-head. If it turns out just to be an elaborated type
12070 specifier, remain silent. */
12071 if (cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/false))
12072 qualified_p = true;
12073
12074 push_deferring_access_checks (dk_no_check);
12075
12076 /* Determine the name of the class. Begin by looking for an
12077 optional nested-name-specifier. */
12078 nested_name_specifier
12079 = cp_parser_nested_name_specifier_opt (parser,
12080 /*typename_keyword_p=*/false,
12081 /*check_dependency_p=*/false,
12082 /*type_p=*/false,
12083 /*is_declaration=*/false);
The entity that follows class-key should be identifier or attribute. See nested-name-specifier also begins with identifier; it first tries nested-name-specifier. Nested-name-specifier may contain following members.
nested-name-specifier
Ⅼ class-or-namespace-name::nested-name-specifier [opt]
├ namespace-name --- identifier
Ⅼ class-name
├ identifier
Ⅼ template-id
See “SingleTheaded” or “SingleThreaded {“ are not valid nested-name-specifiers which requires “::” as the ending token, at line 12079 cp_parser_nested_name_specifier_opt will return NULL to nested_name_specifier.
What’s more, the absence of ‘::’ indicates the identifier should be found by standard name-lookup procedure stipulated by the standard. For the case, it needs clear the scope information in parser, and let the name-lookup procedure sets up it appropriately.
14127 static tree
14128 cp_parser_global_scope_opt (cp_parser* parser, bool current_scope_valid_p) in parser.c
14129 {
14130 cp_token *token;
14131
14132 /* Peek at the next token. */
14133 token = cp_lexer_peek_token (parser->lexer);
14134 /* If we're looking at a `::' token then we're starting from the
14135 global namespace, not our current location. */
14136 if (token->type == CPP_SCOPE)
14137 {
14138 /* Consume the `::' token. */
14139 cp_lexer_consume_token (parser->lexer);
14140 /* Set the SCOPE so that we know where to start the lookup. */
14141 parser->scope = global_namespace;
14142 parser->qualifying_scope = global_namespace;
14143 parser->object_scope = NULL_TREE;
14144
14145 return parser->scope;
14146 }
14147 else if (!current_scope_valid_p)
14148 {
14149 parser->scope = NULL_TREE;
14150 parser->qualifying_scope = NULL_TREE;
14151 parser->object_scope = NULL_TREE;
14152 }
14153
14154 return NULL_TREE;
14155 }
In parser, field scope indicates the scope in which names should be looked up. If NULL_TREE, then we look up names in the scope that is currently open in the source program. If non-NULL, this is either a TYPE or NAMESPACE_DECL for the scope in which we should look. Fields object_scope and qualifying_scope give the scopes in which the last lookup took place. Object_scope is used if an expression like "x->y" or "x.y" was used; it gives the type of "*x" or "x", respectively. Qualifying_scope is used for an expression of the form "X::Y"; it refers to X.
In above function, parameter current_scope_valid_p if false, means depending on currently open scope to solve names. For class declaraction, it is obvious.
cp_parser_class_head (continue)
12084 /* If there was a nested-name-specifier, then there *must* be an
12085 identifier. */
12086 if (nested_name_specifier)
12087 {
…
12143 }
12144 /* Otherwise, the identifier is optional. */
12145 else
12146 {
12147 /* We don't know whether what comes next is a template-id,
12148 an identifier, or nothing at all. */
12149 cp_parser_parse_tentatively (parser);
12150 /* Check for a template-id. */
12151 id = cp_parser_template_id (parser,
12152 /*template_keyword_p=*/false,
12153 /*check_dependency_p=*/true,
12154 /*is_declaration=*/true);
12155 /* If that didn't work, it could still be an identifier. */
12156 if (!cp_parser_parse_definitely (parser))
12157 {
12158 if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
12159 id = cp_parser_identifier (parser);
12160 else
12161 id = NULL_TREE;
12162 }
12163 else
12164 {
12165 template_id_p = true;
12166 ++num_templates;
12167 }
12168 }
12169
12170 pop_deferring_access_checks ();
12171
12172 if (id)
12173 cp_parser_check_for_invalid_template_id (parser, id);
12174
12175 /* If it's not a `:' or a `{' then we can't really be looking at a
12176 class-head, since a class-head only appears as part of a
12177 class-specifier. We have to detect this situation before calling
12178 xref_tag, since that has irreversible side-effects. */
12179 if (!cp_parser_next_token_starts_class_definition_p (parser))
12180 {
12181 cp_parser_error (parser, "expected `{' or `:'");
12182 return error_mark_node;
12183 }
12184
12185 /* At this point, we're going ahead with the class-specifier, even
12186 if some other problem occurs. */
12187 cp_parser_commit_to_tentative_parse (parser);
12188 /* Issue the error about the overly-qualified name now. */
12189 if (qualified_p)
12190 cp_parser_error (parser,
12191 "global qualification of class name is invalid");
12192 else if (invalid_nested_name_p)
12193 cp_parser_error (parser,
12194 "qualified name does not name a class");
12195 else if (nested_name_specifier)
12196 {
…
12232 }
12233 /* An explicit-specialization must be preceded by "template <>". If
12234 it is not, try to recover gracefully. */
12235 if (at_namespace_scope_p ()
12236 && parser->num_template_parameter_lists == 0
12237 && template_id_p)
12238 {
12239 error ("an explicit specialization must be preceded by 'template <>'");
12240 invalid_explicit_specialization_p = true;
12241 /* Take the same action that would have been taken by
12242 cp_parser_explicit_specialization. */
12243 ++parser->num_template_parameter_lists;
12244 begin_specialization ();
12245 }
12246 /* There must be no "return" statements between this point and the
12247 end of this function; set "type "to the correct return value and
12248 use "goto done;" to return. */
12249 /* Make sure that the right number of template parameters were
12250 present. */
12251 if (!cp_parser_check_template_parameters (parser, num_templates))
12252 {
12253 /* If something went wrong, there is no point in even trying to
12254 process the class-definition. */
12255 type = NULL_TREE;
12256 goto done;
12257 }
If before base-clause is template-id, it is a template specialization, for example: “template <> class A <int>: public B { … };”. For normal class template, it should be an identifier. Template-id is a complex structure, we will see it later.
5.12.3.2.1.1.1.1. Sanity check before going ahead
Before going ahead, it needs to check if any error occured. First, token “<” can’t follow a type-specifier, routine cp_parser_check_for_invalid_template_id checks for this error case.
1883 static void
1884 cp_parser_check_for_invalid_template_id (cp_parser* parser, in parser.c
1885 tree type)
1886 {
1887 ptrdiff_t start;
1888 cp_token *token;
1889
1890 if (cp_lexer_next_token_is (parser->lexer, CPP_LESS))
1891 {
1892 if (TYPE_P (type))
1893 error ("`%T' is not a template", type);
1894 else if (TREE_CODE (type) == IDENTIFIER_NODE)
1895 error ("`%s' is not a template", IDENTIFIER_POINTER (type));
1896 else
1897 error ("invalid template-id");
1898 /* Remember the location of the invalid "<". */
1899 if (cp_parser_parsing_tentatively (parser)
1900 && !cp_parser_committed_to_tentative_parse (parser))
1901 {
1902 token = cp_lexer_peek_token (parser->lexer);
1903 token = cp_lexer_prev_token (parser->lexer, token);
1904 start = cp_lexer_token_difference (parser->lexer,
1905 parser->lexer->first_token,
1906 token);
1907 }
1908 else
1909 start = -1;
1910 /* Consume the "<". */
1911 cp_lexer_consume_token (parser->lexer);
1912 /* Parse the template arguments. */
1913 cp_parser_enclosed_template_argument_list (parser);
1914 /* Permanently remove the invalid template arguments so that
1915 this error message is not issued again. */
1916 if (start >= 0)
1917 {
1918 token = cp_lexer_advance_token (parser->lexer,
1919 parser->lexer->first_token,
1920 start);
1921 cp_lexer_purge_tokens_after (parser->lexer, token);
1922 }
1923 }
1924 }
Then it needs to see tokens coming can construct a valid class-head, which must be “{“ or “:”.
15199 static bool
15200 cp_parser_next_token_starts_class_definition_p (cp_parser *parser) in parser.c
15201 {
15202 cp_token *token;
15203
15204 token = cp_lexer_peek_token (parser->lexer);
15205 return (token->type == CPP_OPEN_BRACE || token->type == CPP_COLON);
15206 }
Next for our example, variable template_id_p remains false as the declaration is not a template-id. And also notice that now variable num_templates is still 0.
14018 static bool
14019 cp_parser_check_template_parameters (cp_parser* parser, in parser.c
14020 unsigned num_templates)
14021 {
14022 /* If there are more template classes than parameter lists, we have
14023 something like:
14024
14025 template <class T> void S<T>::R<T>::f (); */
14026 if (parser->num_template_parameter_lists < num_templates)
14027 {
14028 error ("too few template-parameter-lists");
14029 return false;
14030 }
14031 /* If there are the same number of template classes and parameter
14032 lists, that's OK. */
14033 if (parser->num_template_parameter_lists == num_templates)
14034 return true;
14035 /* If there are more, but only one more, then we are referring to a
14036 member template. That's OK too. */
14037 if (parser->num_template_parameter_lists == num_templates + 1)
14038 return true;
14039 /* Otherwise, there are too many template parameter lists. We have
14040 something like:
14041
14042 template <class T> template <class U> void S::f(); */
14043 error ("too many template-parameter-lists");
14044 return false;
14045 }
As we have seen in previous section, slot num_template_parameter_lists of parser records the nested level of template parameter, and num_templates records the nested level of templates has been seen within cp_parser_class_head. For valid declaration, they must match each other.
5.12.3.2.1.1.1.2. Push tag of class SingleThreaded
Now after sanity check, there are three valid cases for token parsed: 1) template-id, it may forms a partial specialized template; 2) no nested-name-specified found, it should be a class type defintiion; 3) nested-name-specifier found, it may be nested class type definition, or class member definition. They need be handled case by case.
Here the “tag” will tell the compiler it is the user-defined type. From here on, this type can be used within type-specifier (if it is just a forward declaration, only limited use permited, e.g. in pointer).
cp_parser_class_head (continue)
12259 /* Look up the type. */
12260 if (template_id_p)
12261 {
12262 type = TREE_TYPE (id);
12263 maybe_process_partial_specialization (type);
12264 }
12265 else if (!nested_name_specifier)
12266 {
12267 /* If the class was unnamed, create a dummy name. */
12268 if (!id)
12269 id = make_anon_name ();
12270 type = xref_tag (class_key, id, /*globalize=*/false,
12271 parser->num_template_parameter_lists);
12272 }
12273 else
12274 {
…
12316 }
Here for our example, as we see, variable nested_name_specifier is NULL, routine xre_tag is invoked. In the function, parameter tag_code indicates the type of tag associating with the name. And tag_type has following definition.
2954 enum tag_types { in cp-tree.h
2955 none_type = 0, /* Not a tag type. */
2956 record_type, /* "struct" types. */
2957 class_type, /* "class" types. */
2958 union_type, /* "union" types. */
2959 enum_type, /* "enum" types. */
2960 typename_type /* "typename" types. */
2961 };
Besides, parameter globalize is false when this is also a definition. Only look in the current scope for the name; template_header_p is true when this declaration is preceded by a set of template parameters (here it is 1, which comes from parser->num_template_parameter_lists).
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 {
...
9556 }
As globalize is false, at invoking lookup_tag, it passes 1 for parameter thislevel_only which indicates to searche only the specified context (but skips any sk_cleanup contexts to find one that is meaningful for tags).
2369 tree
2370 lookup_tag (enum tree_code form, tree name, in name-lookup.c
2371 cxx_scope *binding_level, int thislevel_only)
2372 {
2373 struct cp_binding_level *level;
2374 /* Nonzero if, we should look past a template parameter level, even
2375 if THISLEVEL_ONLY. */
2376 int allow_template_parms_p = 1;
2377 bool type_is_anonymous = ANON_AGGRNAME_P (name);
2378
2379 timevar_push (TV_NAME_LOOKUP);
2380 for (level = binding_level; level; level = level->level_chain)
2381 {
2382 tree tail;
2383 if (type_is_anonymous && level->type_decls != NULL)
2384 {
2385 tree type = binding_table_find_anon_type (level->type_decls, name);
2386 /* There is no need for error checking here, because
2387 anon names are unique throughout the compilation. */
2388 if (type != NULL)
2389 POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, type);
2390 }
2391 else if (level->kind == sk_namespace)
2392 /* Do namespace lookup. */
2393 for (tail = current_namespace; 1; tail = CP_DECL_CONTEXT (tail))
2394 {
2395 cxx_binding *binding =
2396 cxx_scope_find_binding_for_name (NAMESPACE_LEVEL (tail), name);
2397 tree old;
2398
2399 /* If we just skipped past a template parameter level,
2400 even though THISLEVEL_ONLY, and we find a template
2401 class declaration, then we use the _TYPE node for the
2402 template. See the example below. */
2403 if (thislevel_only && !allow_template_parms_p
2404 && binding && binding->value
2405 && DECL_CLASS_TEMPLATE_P (binding->value))
2406 old = binding->value;
2407 else if (binding)
2408 old = select_decl (binding, LOOKUP_PREFER_TYPES);
2409 else
2410 old = NULL_TREE;
2411
2412 if (old)
2413 {
...
2429 }
2430 if (thislevel_only || tail == global_namespace)
2431 POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, NULL_TREE);
2432 }
2433 else if (level->type_decls != NULL)
2434 {
...
2449 }
2450 if (thislevel_only && level->kind != sk_cleanup)
2451 {
2452 if (level->kind == sk_template_parms && allow_template_parms_p)
2453 {
2454 /* We must deal with cases like this:
2455
2456 template <class T> struct S;
2457 template <class T> struct S {};
2458
2459 When looking up `S', for the second declaration, we
2460 would like to find the first declaration. But, we
2461 are in the pseudo-global level created for the
2462 template parameters, rather than the (surrounding)
2463 namespace level. Thus, we keep going one more level,
2464 even though THISLEVEL_ONLY is nonzero. */
2465 allow_template_parms_p = 0;
2466 continue;
2467 }
2468 else
2469 POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, NULL_TREE);
2470 }
2471 }
2472 POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, NULL_TREE);
2473 }
First see that if thislevel_only is 0, it will look up the tag from current scope up till arriving global namespace; but if it is nonzero, the function exits immediately after searching the specified scope. Now we are doing declaration within scope “sk_template_parms” (see it is pushed by begin_template_parm_list); so we will reenter the loop even though thislevel_only is 1. And then do look-up within namespace “Loki”. Of course cxx_scope_find_binding_for_name shouldn’t find anything. As result NULL_TREE will be returned by lookup_tag.
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 {
9578 if (!globalize && processing_template_decl && IS_AGGR_TYPE (t))
9579 redeclare_class_template (t, current_template_parms);
9580 else if (!processing_template_decl
9581 && CLASS_TYPE_P (t)
9582 && CLASSTYPE_IS_TEMPLATE (t))
9583 {
9584 error ("redeclaration of `%T' as a non-template", t);
9585 t = error_mark_node;
9586 }
9587 }
9588
9589 POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, t);
9590 }
When back to xref_tag, variable t at line 9558 will be NULL. Tree node of RECORD_TYPE is created for the type. And see that the name will be pushed into namespace “Loki” by pushtag at line 9573.
Now current_binding_level refers to the cxx_scope object of sk_template_parms. So in WHILE loop at line 4596 below, b is going up to scope of namespace of “Loki”.
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);
Here name refers to node of identifier of “SingleThreaded”, which had not been declared yet, so below at line 4622 IDENTIFIER_TYPE_VALUE returns NULL as result. Also see in xref_tag, TYPE_CONTEXT is NULL for the node.
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);
Routine current_scope will return non-null only if current enclosing type is class (also struct, union) or function, and which returns NULL here. Then variable context is set as namespace “Loki” at line 4641 instead.
Figure 52: Push tag of class SingleThreaded – step 1
After inserting the name into the namespace “Loki” at line 4654, the layout of intermediate tree is roughly like above figure.