在 cp_parser_class_name 的调用中,当且仅当关键字 typename 已经被使用来表示,在依赖类型中查找的名字应该被视为类型时, typename_keyword_p 是 true ;当且仅当关键字 template 已经被使用来表示其次出现的名字是一个模板时, template_keyword_p 是 true ;当且仅当下一个名字应该被视为类名( class-name ),即便它还被声明为其它类别的名字,时, type_p 是 true ;如果 check_dependency_p 是 false ,名字在依赖作用域( dependent scope )中查找;如果 class_head_p 是 true ,这个类是在一个 class-head 中正在被定义的类。
11733 static tree
11734 cp_parser_class_name (cp_parser *parser, in parser.c
11735 bool typename_keyword_p,
11736 bool template_keyword_p,
11737 bool type_p,
11738 bool check_dependency_p,
11739 bool class_head_p,
11740 bool is_declaration)
11741 {
11742 tree decl;
11743 tree scope;
11744 bool typename_p;
11745 cp_token *token;
11746
11747 /* All class-names start with an identifier. */
11748 token = cp_lexer_peek_token (parser->lexer);
11749 if (token->type != CPP_NAME && token->type != CPP_TEMPLATE_ID)
11750 {
11751 cp_parser_error (parser, "expected class-name");
11752 return error_mark_node;
11753 }
11754
11755 /* PARSER->SCOPE can be cleared when parsing the template-arguments
11756 to a template-id, so we save it here. */
11757 scope = parser->scope;
11758 if (scope == error_mark_node)
11759 return error_mark_node;
11760
11761 /* Any name names a type if we're following the `typename' keyword
11762 in a qualified name where the enclosing scope is type-dependent. */
11763 typename_p = (typename_keyword_p && scope && TYPE_P (scope)
11764 && dependent_type_p (scope));
11765 /* Handle the common case (an identifier, but not a template-id)
11766 efficiently. */
在 11764 行, typename_p 为 true ,如果我们在一个限定名里跟在关键字 typename 后面,并且当前作用域是类型依赖的。在 评估类型的依赖性 一节中,看到这表明该名字代表一个类型。回忆只有限定名才会把其所在作用域填充 parser->scope 。
cp_parser_class_name (continue)
11767 if (token->type == CPP_NAME
11768 && !cp_parser_nth_token_starts_template_argument_list_p (parser, 2))
11769 {
11770 tree identifier;
11771
11772 /* Look for the identifier. */
11773 identifier = cp_parser_identifier (parser);
11774 /* If the next token isn't an identifier, we are certainly not
11775 looking at a class-name. */
11776 if (identifier == error_mark_node)
11777 decl = error_mark_node;
11778 /* If we know this is a type-name, there's no need to look it
11779 up. */
11780 else if (typename_p)
11781 decl = identifier;
11782 else
11783 {
11784 /* If the next token is a `::', then the name must be a type
11785 name.
11786
11787 [basic.lookup.qual]
11788
11789 During the lookup for a name preceding the :: scope
11790 resolution operator, object, function, and enumerator
11791 names are ignored. */
11792 if (cp_lexer_next_token_is (parser->lexer, CPP_SCOPE))
11793 type_p = true;
11794 /* Look up the name. */
11795 decl = cp_parser_lookup_name (parser, identifier,
11796 type_p,
11797 /*is_template=*/ false,
11798 /*is_namespace=*/ false,
11799 check_dependency_p);
11800 }
11801 }
对于非 template-id 的情形, 名字查找的细节 一节已经进行了详细的描述。注意 11780 行,如果 typename_p 为 true ,直接返回 identifier ,不做任何查找,因为 identifier 已经代表一个类型。
class-name 的另一个形式是 template-id ,它的语法如下(与【 3 】给出的有点不同):
template-id
Ⅼ template-name < template-argument-list [opt] >
├ identifier ├ template-argument-lis t, template-argument
Ⅼ operator-function-id Ⅼ template-argument
├ assignment-expression
├ type-id
Ⅼ id-expression
一个 conversion-function-id (转换操作符)不能是一个模板名,因为它们不能是构成 template-id 的部分。事实上,看到这样的代码:
a.operator K<int>()
该 conversion-function-id 是“ operator K<int> ”,而 K<int> 是一个 type-id 。不可能通过显式实参列表来调用一个模板化的 conversion-function-id ,因为唯一允许的模板实参是其要转换的类型。
cp_parser_class_name (continue)
11802 else
11803 {
11804 /* Try a template-id. */
11805 decl = cp_parser_template_id (parser, template_keyword_p,
11806 check_dependency_p,
11807 is_declaration);
11808 if (decl == error_mark_node)
11809 return error_mark_node;
11810 }
此处参数 template_keyword_p 如果是 true 表示我们看到了关键字 template 。比如: T::template f<3> () 。
7867 static tree
7868 cp_parser_template_id (cp_parser *parser, in parser.c
7869 bool template_keyword_p,
7870 bool check_dependency_p,
7871 bool is_declaration)
7872 {
7873 tree template;
7874 tree arguments;
7875 tree template_id;
7876 ptrdiff_t start_of_id;
7877 tree access_check = NULL_TREE;
7878 cp_token *next_token, *next_token_2;
7879 bool is_identifier;
7880
7881 /* If the next token corresponds to a template-id, there is no need
7882 to reparse it. */
7883 next_token = cp_lexer_peek_token (parser->lexer);
7884 if (next_token->type == CPP_TEMPLATE_ID)
7885 {
7886 tree value;
7887 tree check;
7888
7889 /* Get the stored value. */
7890 value = cp_lexer_consume_token (parser->lexer)->value;
7891 /* Perform any access checks that were deferred. */
7892 for (check = TREE_PURPOSE (value); check; check = TREE_CHAIN (check))
7893 perform_or_defer_access_check (TREE_PURPOSE (check),
7894 TREE_VALUE (check));
7895 /* Return the stored value. */
7896 return TREE_VALUE (value);
7897 }
7898
7899 /* Avoid performing name lookup if there is no possibility of
7900 finding a template-id. */
7901 if ((next_token->type != CPP_NAME && next_token->keyword != RID_OPERATOR)
7902 || (next_token->type == CPP_NAME
7903 && !cp_parser_nth_token_starts_template_argument_list_p
7904 (parser, 2)))
7905 {
7906 cp_parser_error (parser, "expected template-id");
7907 return error_mark_node;
7908 }
7909
7910 /* Remember where the template-id starts. */
7911 if (cp_parser_parsing_tentatively (parser)
7912 && !cp_parser_committed_to_tentative_parse (parser))
7913 {
7914 next_token = cp_lexer_peek_token (parser->lexer);
7915 start_of_id = cp_lexer_token_difference (parser->lexer,
7916 parser->lexer->first_token,
7917 next_token);
7918 }
7919 else
7920 start_of_id = -1;
7921
7922 push_deferring_access_checks (dk_deferred);
7923
7924 /* Parse the template-name. */
7925 is_identifier = false;
7926 template = cp_parser_template_name (parser, template_keyword_p,
7927 check_dependency_p,
7928 is_declaration,
7929 &is_identifier);
7930 if (template == error_mark_node || is_identifier)
7931 {
7932 pop_deferring_access_checks ();
7933 return template;
7934 }
如果该 template-id 之前已经被成功解析过(对于尝试性解析器来说,对一段复杂模板代码的解析可能需要多次尝试,把已经成功解析的结构保存起来,可以加速编译的速度。类似的结构还有 nest-name-specifier ),解析器已经为把这些符号用结构 CPP_TEMLATE_ID 来代替。在后面我们可以看到该节点的细节。
如果未曾解析,则按部就班执行以下步骤。
5.12.4.2.2.2.1. 解析模板名
模板名可以是标识符或者 operator-function-id 。除此之外都不对。上面 7901 行的检查保证了这一点。另外,我们需要记住开始解析 template-id 的地方( 7915 行的 start_of_id ),一旦解析成功,我们需要把这些符号都替换掉。
8088 static tree
8089 cp_parser_template_name (cp_parser* parser, in parser.c
8090 bool template_keyword_p,
8091 bool check_dependency_p,
8092 bool is_declaration,
8093 bool *is_identifier)
8094 {
8095 tree identifier;
8096 tree decl;
8097 tree fns;
8098
8099 /* If the next token is `operator', then we have either an
8100 operator-function-id or a conversion-function-id. */
8101 if (cp_lexer_next_token_is_keyword (parser->lexer, RID_OPERATOR))
8102 {
8103 /* We don't know whether we're looking at an
8104 operator-function-id or a conversion-function-id. */
8105 cp_parser_parse_tentatively (parser);
8106 /* Try an operator-function-id. */
8107 identifier = cp_parser_operator_function_id (parser);
8108 /* If that didn't work, try a conversion-function-id. */
8109 if (!cp_parser_parse_definitely (parser))
8110 {
8111 cp_parser_error (parser, "expected template-name");
8112 return error_mark_node;
8113 }
8114 }
8115 /* Look for the identifier. */
8116 else
8117 identifier = cp_parser_identifier (parser);
5.12.4.2.2.1.1.1. Operator-function-id
如果看到关键字 operator ,解析器将尝试 operator-function-id ,其规则如下:
operator-function-id:
operator operator
注意第二个 operator 不是终结符,它包含了如下的终结符:
operator:
new delete new[] delete[] + - * / % ^ & | ~ ! = < >
+= -= *= /= %= ^= &= |= << >> >>= <<= == != <= >= && || ++ -- , ->* -> () []
7307 static tree
7308 cp_parser_operator_function_id (cp_parser* parser) in parser.c
7309 {
7310 /* Look for the `operator' keyword. */
7311 if (!cp_parser_require_keyword (parser, RID_OPERATOR, "`operator'"))
7312 return error_mark_node;
7313 /* And then the name of the operator itself. */
7314 return cp_parser_operator (parser);
7315 }
在 初始化操作符数据 一节,关于操作符的信息从配置文件 operator.def 中提取出来,并且记录在全局数组 operator_name_info 及 assignment_operator_name_info 。在 cp_parser_operator 中,该函数将返回该操作符对应的标识符节点,这个标识符是唯一的。而后编译器将根据该标识符产生代码。
7332 static tree
7333 cp_parser_operator (cp_parser* parser) in parser.c
7334 {
7335 tree id = NULL_TREE;
7336 cp_token *token;
7337
7338 /* Peek at the next token. */
7339 token = cp_lexer_peek_token (parser->lexer);
7340 /* Figure out which operator we have. */
7341 switch (token->type)
7342 {
7343 case CPP_KEYWORD:
7344 {
7345 enum tree_code op;
7346
7347 /* The keyword should be either `new' or `delete'. */
7348 if (token->keyword == RID_NEW)
7349 op = NEW_EXPR;
7350 else if (token->keyword == RID_DELETE)
7351 op = DELETE_EXPR;
7352 else
7353 break ;
7354
7355 /* Consume the `new' or `delete' token. */
7356 cp_lexer_consume_token (parser->lexer);
7357
7358 /* Peek at the next token. */
7359 token = cp_lexer_peek_token (parser->lexer);
7360 /* If it's a `[' token then this is the array variant of the
7361 operator. */
7362 if (token->type == CPP_OPEN_SQUARE)
7363 {
7364 /* Consume the `[' token. */
7365 cp_lexer_consume_token (parser->lexer);
7366 /* Look for the `]' token. */
7367 cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'");
7368 id = ansi_opname (op == NEW_EXPR
7369 ? VEC_NEW_EXPR : VEC_DELETE_EXPR);
7370 }
7371 /* Otherwise, we have the non-array variant. */
7372 else
7373 id = ansi_opname (op);
7374
7375 return id;
7376 }
7377
7378 case CPP_PLUS:
7379 id = ansi_opname (PLUS_EXPR);
7380 break ;
…
7522 case CPP_OPEN_PAREN:
7523 /* Consume the `('. */
7524 cp_lexer_consume_token (parser->lexer);
7525 /* Look for the matching `)'. */
7526 cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
7527 return ansi_opname (CALL_EXPR);
7528
7529 case CPP_OPEN_SQUARE:
7530 /* Consume the `['. */
7531 cp_lexer_consume_token (parser->lexer);
7532 /* Look for the matching `]'. */
7533 cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'");
7534 return ansi_opname (ARRAY_REF);
7535
7536 /* Extensions. */
7537 case CPP_MIN:
7538 id = ansi_opname (MIN_EXPR);
7539 break ;
7540
7541 case CPP_MAX:
7542 id = ansi_opname (MAX_EXPR);
7543 break ;
7544
7545 case CPP_MIN_EQ:
7546 id = ansi_assopname (MIN_EXPR);
7547 break ;
7548
7549 case CPP_MAX_EQ:
7550 id = ansi_assopname (MAX_EXPR);
7551 break ;
7552
7553 default :
7554 /* Anything else is an error. */
7555 break ;
7556 }
7557
7558 /* If we have selected an identifier, we need to consume the
7559 operator token. */
7560 if (id)
7561 cp_lexer_consume_token (parser->lexer);
7562 /* Otherwise, no valid operator name was present. */
7563 else
7564 {
7565 cp_parser_error (parser, "expected operator");
7566 id = error_mark_node;
7567 }
7568
7569 return id;
7570 }
显然,宏 ansi_opname 及 ansi_assopname 从数组中返回标识符。
868 #define ansi_opname(CODE) / in cp-tree.h
869 (operator_name_info [(int) (CODE)].identifier)
870 #define ansi_assopname (CODE) /
871 (assignment_operator_name_info [(int) (CODE)].identifier)
5.12.4.2.2.1.1.2. 标识符
根据【 3 】,当一个成员模板特化的名字,在一个 postfix-expression 中出现在“ . ”或“ -> ”之后,或者在一个 qualified-id 中在 nested-name-specifier 之后;并且该 postfix-expression 或 qualified-id 显式地依赖于一个模板参数,该成员模板名必须有关键字 template 作为前缀。否则该名字被假定为一个非模板名。例如:
class X {
public :
template <size_t> X* alloc();
template <size_t> static X* adjust();
};
template <class T> void f(T* p) {
T* p1 = p->alloc<200>(); // ill-formed: < means less than
T* p2 = p->template alloc<200>(); // OK: < starts template argument list
T::adjust<100>(); // ill-formed: < means less than
T::template adjust<100>(); // OK: < starts template argument list
}
以“ T::adjust<100>(); ”为例,当解析这个语句时,此时, is_declaration 是 true ,又因为没有看到 template , template_keyword_p 是 false ,“ parser->scope ”则指向 T ,“ TYPE_P (parser->scope) ”及“ dependent_type_p (parser->scope) ”返回 true ,因此满足 8145 行的条件。作为一个显著例外,构造函数和析构函数不要求在其名字前使用关键字 template ,因为它们的名字都是依赖性的。对于错误的情形, 8153 到 8198 行的代码给出合适的错误信息,并消耗掉构成错误结构的符号。
cp_parser_template_name (continue)
8119 /* If we didn't find an identifier, we don't have a template-id. */
8120 if (identifier == error_mark_node)
8121 return error_mark_node;
8122
8123 /* If the name immediately followed the `template' keyword, then it
8124 is a template-name. However, if the next token is not `<', then
8125 we do not treat it as a template-name, since it is not being used
8126 as part of a template-id. This enables us to handle constructs
8127 like:
8128
8129 template <typename T> struct S { S(); };
8130 template <typename T> S<T>::S();
8131
8132 correctly. We would treat `S' as a template -- if it were `S<T>'
8133 -- but we do not if there is no `<'. */
8134
8135 if (processing_template_decl
8136 && cp_parser_nth_token_starts_template_argument_list_p (parser, 1))
8137 {
8138 /* In a declaration, in a dependent context, we pretend that the
8139 "template" keyword was present in order to improve error
8140 recovery. For example, given:
8141
8142 template <typename T> void f(T::X<int>);
8143
8144 we want to treat "X<int>" as a template-id. */
8145 if (is_declaration
8146 && !template_keyword_p
8147 && parser->scope && TYPE_P (parser->scope)
8148 && check_dependency_p
8149 && dependent_type_p (parser->scope)
8150 /* Do not do this for dtors (or ctors), since they never
8151 need the template keyword before their name. */
8152 && !constructor_name_p (identifier, parser->scope))
8153 {
8154 ptrdiff_t start;
8155 cp_token* token;
8156 /* Explain what went wrong. */
8157 error ("non-template `%D' used as template", identifier);
8158 inform ("use `%T::template %D' to indicate that it is a template",
8159 parser->scope, identifier);
8160 /* If parsing tentatively, find the location of the "<"
8161 token. */
8162 if (cp_parser_parsing_tentatively (parser)
8163 && !cp_parser_committed_to_tentative_parse (parser))
8164 {
8165 cp_parser_simulate_error (parser);
8166 token = cp_lexer_peek_token (parser->lexer);
8167 token = cp_lexer_prev_token (parser->lexer, token);
8168 start = cp_lexer_token_difference (parser->lexer,
8169 parser->lexer->first_token,
8170 token);
8171 }
8172 else
8173 start = -1;
8174 /* Parse the template arguments so that we can issue error
8175 messages about them. */
8176 cp_lexer_consume_token (parser->lexer);
8177 cp_parser_enclosed_template_argument_list (parser);
8178 /* Skip tokens until we find a good place from which to
8179 continue parsing. */
8180 cp_parser_skip_to_closing_parenthesis (parser,
8181 /*recovering=*/ true,
8182 /*or_comma=*/ true,
8183 /*consume_paren=*/ false);
8184 /* If parsing tentatively, permanently remove the
8185 template argument list. That will prevent duplicate
8186 error messages from being issued about the missing
8187 "template" keyword. */
8188 if (start >= 0)
8189 {
8190 token = cp_lexer_advance_token (parser->lexer,
8191 parser->lexer->first_token,
8192 start);
8193 cp_lexer_purge_tokens_after (parser->lexer, token);
8194 }
8195 if (is_identifier)
8196 *is_identifier = true;
8197 return identifier;
8198 }
8199
8200 /* If the "template" keyword is present, then there is generally
8201 no point in doing name-lookup, so we just return IDENTIFIER.
8202 But, if the qualifying scope is non-dependent then we can
8203 (and must) do name-lookup normally. */
8204 if (template_keyword_p
8205 && (!parser->scope
8206 || (TYPE_P (parser->scope)
8207 && dependent_type_p (parser->scope))))
8208 return identifier;
8209 }
如果找到的标识符没有依赖性,应该立刻查找以解析这个名字。如果该名字是有效的,那么 cp_parser_lookup_name 将返回代表当前与该名字绑定的声明的节点,并且注意到在此刻我们接受任何匹配的东西。类似的,如果我们找到的是一个 baselink ,而它指向一个重载函数链表,前端则进入这个链表并找出作为模板声明的那个,因为我们正在查找模板名,如果找不到就给出错误消息。
cp_parser_template_name (continue)
8211 /* Look up the name. */
8212 decl = cp_parser_lookup_name (parser, identifier,
8213 /*is_type=*/ false,
8214 /*is_template=*/ false,
8215 /*is_namespace=*/ false,
8216 check_dependency_p);
8217 decl = maybe_get_template_decl_from_type_decl (decl);
8218
8219 /* If DECL is a template, then the name was a template-name. */
8220 if (TREE_CODE (decl) == TEMPLATE_DECL)
8221 ;
8222 else
8223 {
8224 tree fn = NULL_TREE;
8225
8226 /* The standard does not explicitly indicate whether a name that
8227 names a set of overloaded declarations, some of which are
8228 templates, is a template-name. However, such a name should
8229 be a template-name; otherwise, there is no way to form a
8230 template-id for the overloaded templates. */
8231 fns = BASELINK_P (decl) ? BASELINK_FUNCTIONS (decl) : decl;
8232 if (TREE_CODE (fns) == OVERLOAD)
8233 for (fn = fns; fn; fn = OVL_NEXT (fn))
8234 if (TREE_CODE (OVL_CURRENT (fn)) == TEMPLATE_DECL)
8235 break ;
8236
8237 if (!fn)
8238 {
8239 /* Otherwise, the name does not name a template. */
8240 cp_parser_error (parser, "expected template-name");
8241 return error_mark_node;
8242 }
8243 }
8244
8245 /* If DECL is dependent, and refers to a function, then just return
8246 its name; we will look it up again during template instantiation. */
8247 if (DECL_FUNCTION_TEMPLATE_P (decl) || !DECL_P (decl))
8248 {
8249 tree scope = CP_DECL_CONTEXT (get_first_fn (decl));
8250 if (TYPE_P (scope) && dependent_type_p (scope))
8251 return identifier;
8252 }
8253
8254 return decl;
8255 }
对于类模板,我们已经看到,至少有 2 个 TYPE_DECL 被构建。一个对应于声明,而另一个表示对自己的引用;两者都引用类的 RECORD_TYPE 节点。此处被提取的 TYPE_DECL 是对自己引用的那个(看到从类节点的 bindings 域,导向的是对自己引用的 TYPE_DECL ),不过这个节点对于模板声明并不合适。因此由 CLASSTYPE_TI_TEMPLATE 进一步返回 TEMPLATE_DECL 节点。
4105 tree
4106 maybe_get_template_decl_from_type_decl (tree decl) in pt.c
4107 {
4108 return (decl != NULL_TREE
4109 && TREE_CODE (decl) == TYPE_DECL
4110 && DECL_ARTIFICIAL (decl)
4111 && CLASS_TYPE_P (TREE_TYPE (decl))
4112 && CLASSTYPE_TEMPLATE_INFO (TREE_TYPE (decl)))
4113 ? CLASSTYPE_TI_TEMPLATE (TREE_TYPE (decl)) : decl;
4114 }
在为模板名找到合适的节点后,这个名字必须后跟一对尖括号。不过,有一个特殊的情形必须考虑。就是当看到“ <:: ”时,如果允许复合字母拼写( digraph spelling ),“ <: ”将被解释为“ [ ”,从而给出结果“ [: ”(这由词法分析器完成)。因此如果我们看到“ [: ”跟在模板名后,我们需要将它转换回“ <:: ”(如果程序员误写了“ [: ”,解析器可以自动地纠正这个错误,看上去很酷 so cool )。这个不好的用法将导致一个警告。
cp_parser_template_id (continue)
7936 /* If we find the sequence `[:' after a template-name, it's probably
7937 a digraph-typo for `< ::'. Substitute the tokens and check if we can
7938 parse correctly the argument list. */
7939 next_token = cp_lexer_peek_nth_token (parser->lexer, 1);
7940 next_token_2 = cp_lexer_peek_nth_token (parser->lexer, 2);
7941 if (next_token->type == CPP_OPEN_SQUARE
7942 && next_token->flags & DIGRAPH
7943 && next_token_2->type == CPP_COLON
7944 && !(next_token_2->flags & PREV_WHITE))
7945 {
7946 cp_parser_parse_tentatively (parser);
7947 /* Change `:' into `::'. */
7948 next_token_2->type = CPP_SCOPE;
7949 /* Consume the first token (CPP_OPEN_SQUARE - which we pretend it is
7950 CPP_LESS. */
7951 cp_lexer_consume_token (parser->lexer);
7952 /* Parse the arguments. */
7953 arguments = cp_parser_enclosed_template_argument_list (parser);
7954 if (!cp_parser_parse_definitely (parser))
7955 {
7956 /* If we couldn't parse an argument list, then we revert our changes
7957 and return simply an error. Maybe this is not a template-id
7958 after all. */
7959 next_token_2->type = CPP_COLON;
7960 cp_parser_error (parser, "expected `<'");
7961 pop_deferring_access_checks ();
7962 return error_mark_node;
7963 }
7964 /* Otherwise, emit an error about the invalid digraph, but continue
7965 parsing because we got our argument list. */
7966 pedwarn ("`<::' cannot begin a template-argument list");
7967 inform ("`<:' is an alternate spelling for `['. Insert whitespace "
7968 "between `<' and `::'");
7969 if (!flag_permissive )
7970 {
7971 static bool hint;
7972 if (!hint)
7973 {
7974 inform ("(if you use `-fpermissive' G++ will accept your code)");
7975 hint = true;
7976 }
7977 }
7978 }
7979 else
7980 {
7981 /* Look for the `<' that starts the template-argument-list. */
7982 if (!cp_parser_require (parser, CPP_LESS, "`<'"))
7983 {
7984 pop_deferring_access_checks ();
7985 return error_mark_node;
7986 }
7987 /* Parse the arguments. */
7988 arguments = cp_parser_enclosed_template_argument_list (parser);
7989 }
“ <> ”之间的就是实参列表。对于函数模板,实参列表可以是空的,只要从函数的调用实参可以无二义性地推导出模板实参。