GCC-3.4.6源代码学习笔记(122)
2010-11-05 09:00
295 查看
5.12.4.2.2.
类名查找
在
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
}
5.12.4.2.2.1.
非
template-id
对于非
template-id
的情形,
名字查找的细节
一节已经进行了详细的描述。注意
11780
行,如果
typename_p
为
true
,直接返回
identifier
,不做任何查找,因为
identifier
已经代表一个类型。
5.12.4.2.2.2.
Template-id
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
}
“
<>
”之间的就是实参列表。对于函数模板,实参列表可以是空的,只要从函数的调用实参可以无二义性地推导出模板实参。
类名查找
在
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
}
5.12.4.2.2.1.
非
template-id
对于非
template-id
的情形,
名字查找的细节
一节已经进行了详细的描述。注意
11780
行,如果
typename_p
为
true
,直接返回
identifier
,不做任何查找,因为
identifier
已经代表一个类型。
5.12.4.2.2.2.
Template-id
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
}
“
<>
”之间的就是实参列表。对于函数模板,实参列表可以是空的,只要从函数的调用实参可以无二义性地推导出模板实参。
相关文章推荐
- GCC-3.4.6源代码学习笔记(159)
- GCC-3.4.6源代码学习笔记(83)
- GCC-3.4.6源代码学习笔记(26)
- GCC-3.4.6源代码学习笔记(87)
- GCC-3.4.6源代码学习笔记(26续2)
- GCC-3.4.6源代码学习笔记(140 - 续)
- GCC-3.4.6源代码学习笔记(35)
- GCC-3.4.6源代码学习笔记(66)
- GCC-3.4.6源代码学习笔记(48)
- GCC-3.4.6源代码学习笔记(173)
- GCC-3.4.6源代码学习笔记 (101)
- GCC-3.4.6源代码学习笔记(74)
- GCC-3.4.6源代码学习笔记 (104)
- GCC-3.4.6源代码学习笔记(80)
- GCC-3.4.6源代码学习笔记(177)
- GCC-3.4.6源代码学习笔记(81)
- GCC-3.4.6源代码学习笔记(138)
- GCC-3.4.6源代码学习笔记(25)
- GCC-3.4.6源代码学习笔记(84)
- GCC-3.4.6源代码学习笔记(5)