5.12.1.2. Parse decl-specifier-seq part of template declaration
During parsing, we may encounter error statement, to continue parsing as possible, it is prefer to advance to the nearest “>” (of course, if the statement is correct, the next token should be “>”). Next for parsing member template like:
template<class T> class string {
public:
template<class T2> int compare(const T2&);
template<class T2> string(const string<T2>& s) { /* ... */ }
// ...
};
template<class T> template<class T2> int string<T>::compare(const T2& s) {}
At line 14458 checks for the part “template<class T2>” of the method and processes it in recursion at line 14460.
cp_parser_template_declaration_after_export (continue)
14452 /* Look for the `>'. */
14453 cp_parser_skip_until_found (parser, CPP_GREATER, "`>'");
14454 /* We just processed one more parameter list. */
14455 ++parser->num_template_parameter_lists;
14456 /* If the next token is `template', there are more template
14457 parameters. */
14458 if (cp_lexer_next_token_is_keyword (parser->lexer,
14459 RID_TEMPLATE))
14460 cp_parser_template_declaration_after_export (parser, member_p);
14461 else
14462 {
14463 decl = cp_parser_single_declaration (parser,
14464 member_p,
14465 &friend_p);
14466
14467 /* If this is a member template declaration, let the front
14468 end know. */
14469 if (member_p && !friend_p && decl)
14470 {
14471 if (TREE_CODE (decl) == TYPE_DECL)
14472 cp_parser_check_access_in_redeclaration (decl);
14473
14474 decl = finish_member_template_decl (decl);
14475 }
14476 else if (friend_p && decl && TREE_CODE (decl) == TYPE_DECL)
14477 make_friend_class (current_class_type, TREE_TYPE (decl),
14478 /*complain=*/true);
14479 }
In the statement of our run-through example, the unparsed part is: “class SingleThreaded {…”; according to the syntax rule, it should be decl-specifier-seq. Structure decl-specifier-seq contains sequence of decl-specifier, which is a complex structure shown in below.
14508 static tree
14509 cp_parser_single_declaration (cp_parser* parser, in parser.c
14510 bool member_p,
14511 bool* friend_p)
14512 {
14513 int declares_class_or_enum;
14514 tree decl = NULL_TREE;
14515 tree decl_specifiers;
14516 tree attributes;
14517 bool function_definition_p = false;
14518
14519 /* This function is only used when processing a template
14520 declaration. */
14521 if (innermost_scope_kind () != sk_template_parms
14522 && innermost_scope_kind () != sk_template_spec)
14523 abort ();
14524
14525 /* Defer access checks until we know what is being declared. */
14526 push_deferring_access_checks (dk_deferred);
14527
14528 /* Try the `decl-specifier-seq [opt] init-declarator [opt]'
14529 alternative. */
14530 decl_specifiers
14531 = cp_parser_decl_specifier_seq (parser,
14532 CP_PARSER_FLAGS_OPTIONAL,
14533 &attributes,
14534 &declares_class_or_enum);
14535 if (friend_p)
14536 *friend_p = cp_parser_friend_p (decl_specifiers);
14537
14538 /* There are no template typedefs. */
14539 if (cp_parser_typedef_p (decl_specifiers))
14540 {
14541 error ("template declaration of `typedef'");
14542 decl = error_mark_node;
14543 }
14544
14545 /* Gather up the access checks that occurred the
14546 decl-specifier-seq. */
14547 stop_deferring_access_checks ();
In below function, if declares_class_or_enum is non-null, *declares_class_or_enum is set to the bitwise or of the following flags:
1: one of the decl-specifiers is an elaborated-type-specifier (i.e., a type declaration)
2: one of the decl-specifiers is an enum-specifier or a class-specifier (i.e., a type definition)
6642 static tree
6643 cp_parser_decl_specifier_seq (cp_parser* parser, in parser.c
6644 cp_parser_flags flags,
6645 tree* attributes,
6646 int* declares_class_or_enum)
6647 {
6648 tree decl_specs = NULL_TREE;
6649 bool friend_p = false;
6650 bool constructor_possible_p = !parser->in_declarator_p;
6651
6652 /* Assume no class or enumeration type is declared. */
6653 *declares_class_or_enum = 0;
6654
6655 /* Assume there are no attributes. */
6656 *attributes = NULL_TREE;
6657
6658 /* Keep reading specifiers until there are no more to read. */
6659 while (true)
6660 {
6661 tree decl_spec = NULL_TREE;
6662 bool constructor_p;
6663 cp_token *token;
6664
6665 /* Peek at the next token. */
6666 token = cp_lexer_peek_token (parser->lexer);
6667 /* Handle attributes. */
6668 if (token->keyword == RID_ATTRIBUTE)
6669 {
6670 /* Parse the attributes. */
6671 decl_spec = cp_parser_attributes_opt (parser);
6672 /* Add them to the list. */
6673 *attributes = chainon (*attributes, decl_spec);
6674 continue;
6675 }
We skip GCC entension attribution above and go on for the handling of decl-specifier excluding type-specifier. See that among these items, friend, function-specifier, typedef, storage-class-specifier must be followed by type-specifier (see the break statement). Local variable decl_spec records the information about these items.
cp_parser_decl_specifier_seq (continue)
6676 /* If the next token is an appropriate keyword, we can simply
6677 add it to the list. */
6678 switch (token->keyword)
6679 {
6680 case RID_FRIEND:
6681 /* decl-specifier:
6682 friend */
6683 if (friend_p)
6684 error ("duplicate `friend'");
6685 else
6686 friend_p = true;
6687 /* The representation of the specifier is simply the
6688 appropriate TREE_IDENTIFIER node. */
6689 decl_spec = token->value;
6690 /* Consume the token. */
6691 cp_lexer_consume_token (parser->lexer);
6692 break;
6693
6694 /* function-specifier:
6695 inline
6696 virtual
6697 explicit */
6698 case RID_INLINE:
6699 case RID_VIRTUAL:
6700 case RID_EXPLICIT:
6701 decl_spec = cp_parser_function_specifier_opt (parser);
6702 break;
6703
6704 /* decl-specifier:
6705 typedef */
6706 case RID_TYPEDEF:
6707 /* The representation of the specifier is simply the
6708 appropriate TREE_IDENTIFIER node. */
6709 decl_spec = token->value;
6710 /* Consume the token. */
6711 cp_lexer_consume_token (parser->lexer);
6712 /* A constructor declarator cannot appear in a typedef. */
6713 constructor_possible_p = false;
6714 /* The "typedef" keyword can only occur in a declaration; we
6715 may as well commit at this point. */
6716 cp_parser_commit_to_tentative_parse (parser);
6717 break;
6718
6719 /* storage-class-specifier:
6720 auto
6721 register
6722 static
6723 extern
6724 mutable
6725
6726 GNU Extension:
6727 thread */
6728 case RID_AUTO:
6729 case RID_REGISTER:
6730 case RID_STATIC:
6731 case RID_EXTERN:
6732 case RID_MUTABLE:
6733 case RID_THREAD:
6734 decl_spec = cp_parser_storage_class_specifier_opt (parser);
6735 break;
6736
6737 default:
6738 break;
6739 }
Routine cp_parser_function_specifier_opt and cp_parser_storage_class_specifier_opt just double check expected token fetched.
In the language, decl-specifier-seq specify how names are to be interpreted, while a declarator delcares a single object, function, or type, within a declaration. Considering constructor, for example:
class A {
public:
A();
};
In A(); A should not be parsed as decl-specifier, it is not declaration, instead it is declarator. Notice that A() aligns with the format of simple-declaration, it hasn’t decl-specifier part. As it is a such special case, it needs be handled specially. Of course, it will not be a problem during parsing declarator, note that at line 6713, constructor_possible_p is the reverse of in_declarator_p slot in parser which is true during parsing declarator.
cp_parser_decl_specifier_seq (continue)
6741 /* Constructors are a special case. The `S' in `S()' is not a
6742 decl-specifier; it is the beginning of the declarator. */
6743 constructor_p = (!decl_spec
6744 && constructor_possible_p
6745 && cp_parser_constructor_declarator_p (parser,
6746 friend_p));
Also notice that parsing of constructor here never consumes tokens no matter it successes or not as it is not decl-specifier but declarator. And finding it just means error. To avoid deviating to far away from our focus, we just skip the parsing of constructor here temperarily.
5.12.3.2.1. Parse type-specifier
If above cases can’t be found, now we can try type-specifier as below. Type-specifier is the key part of decl-specifier-seq, which is the major part of the declaration.
cp_parser_decl_specifier_seq (continue)
6748 /* If we don't have a DECL_SPEC yet, then we must be looking at
6749 a type-specifier. */
6750 if (!decl_spec && !constructor_p)
6751 {
6752 int decl_spec_declares_class_or_enum;
6753 bool is_cv_qualifier;
6754
6755 decl_spec
6756 = cp_parser_type_specifier (parser, flags,
6757 friend_p,
6758 /*is_declaration=*/true,
6759 &decl_spec_declares_class_or_enum,
6760 &is_cv_qualifier);
6761
6762 *declares_class_or_enum |= decl_spec_declares_class_or_enum;
6763
6764 /* If this type-specifier referenced a user-defined type
6765 (a typedef, class-name, etc.), then we can't allow any
6766 more such type-specifiers henceforth.
6767
6768 [dcl.spec]
6769
6770 The longest sequence of decl-specifiers that could
6771 possibly be a type name is taken as the
6772 decl-specifier-seq of a declaration. The sequence shall
6773 be self-consistent as described below.
6774
6775 [dcl.type]
6776
6777 As a general rule, at most one type-specifier is allowed
6778 in the complete decl-specifier-seq of a declaration. The
6779 only exceptions are the following:
6780
6781 -- const or volatile can be combined with any other
6782 type-specifier.
6783
6784 -- signed or unsigned can be combined with char, long,
6785 short, or int.
6786
6787 -- ..
6788
6789 Example:
6790
6791 typedef char* Pc;
6792 void g (const int Pc);
6793
6794 Here, Pc is *not* part of the decl-specifier seq; it's
6795 the declarator. Therefore, once we see a type-specifier
6796 (other than a cv-qualifier), we forbid any additional
6797 user-defined types. We *do* still allow things like `int
6798 int' to be considered a decl-specifier-seq, and issue the
6799 error message later. */
6800 if (decl_spec && !is_cv_qualifier)
6801 flags |= CP_PARSER_FLAGS_NO_USER_DEFINED_TYPES;
6802 /* A constructor declarator cannot follow a type-specifier. */
6803 if (decl_spec)
6804 constructor_possible_p = false;
6805 }
The abbreviate syntax tree of type-specifier is shown in below.
type-specifier
├ simple-type-specifier
├ class-specifier
├ enum-specifier
├ elaborated-type-specifier
├ cv-qualifier
GUN ext Ⅼ __complex__
In below function, parameter declares_class_or_enum if non-null, and the type-specifier is a class-specifier, enum-specifier, or elaborated-type-specifier, then *declares_class_or_enum is set to a nonzero value. The value is 1 if a type is declared, 2 if it is defined; otherwise, it is set to zero. And if is_cv_qualifier is non-null, and the type-specifier is a cv-qualifier, then *is_cv_qualifier is set to true; otherwise, it is set to false.
8713 static tree
8714 cp_parser_type_specifier (cp_parser* parser, in parser.c
8715 cp_parser_flags flags,
8716 bool is_friend,
8717 bool is_declaration,
8718 int* declares_class_or_enum,
8719 bool* is_cv_qualifier)
8720 {
8721 tree type_spec = NULL_TREE;
8722 cp_token *token;
8723 enum rid keyword;
8724
8725 /* Assume this type-specifier does not declare a new type. */
8726 if (declares_class_or_enum)
8727 *declares_class_or_enum = 0;
8728 /* And that it does not specify a cv-qualifier. */
8729 if (is_cv_qualifier)
8730 *is_cv_qualifier = false;
8731 /* Peek at the next token. */
8732 token = cp_lexer_peek_token (parser->lexer);
8733
8734 /* If we're looking at a keyword, we can use that to guide the
8735 production we choose. */
8736 keyword = token->keyword;
8737 switch (keyword)
8738 {
8739 case RID_ENUM:
...
8763 /* Any of these indicate either a class-specifier, or an
8764 elaborated-type-specifier. */
8765 case RID_CLASS:
8766 case RID_STRUCT:
8767 case RID_UNION:
8768 /* Parse tentatively so that we can back up if we don't find a
8769 class-specifier or enum-specifier. */
8770 cp_parser_parse_tentatively (parser);
8771 /* Look for the class-specifier. */
8772 type_spec = cp_parser_class_specifier (parser);
8773 /* If that worked, we're done. */
8774 if (cp_parser_parse_definitely (parser))
8775 {
8776 if (declares_class_or_enum)
8777 *declares_class_or_enum = 2;
8778 return type_spec;
8779 }
The coming tokens of the second statement of our example form the class-specifier. They are further handled by cp_parser_class_specifier.