GCC-3.4.6源代码学习笔记(123)
2010-11-05 09:14
525 查看
5.12.4.2.2.2.2.
解析实参列表
然后调用
cp_parser_enclosed_template_argument_list
来解析
template-id
中所包含的模板实参列表。在这个处理之前,
parser
的
greater_than_is_operator_p
域将被设置为
false
,因为从现在起进来的“
>
”将不被视为操作符。而在实参列表中输入的“
>>
”将被解析作“
>
”和“
>
”,例如,“
A<B<>> a
”,前端将把它视为“
A<B<> > a
”。看到解析器将尝试从这个错误恢复并继续前行,但不保证可以产生正确的代码,因为程序员在这里犯了错误,因此给出错误信息。
14692
static
tree
14693
cp_parser_enclosed_template_argument_list
(cp_parser* parser)
in
parser.c
14694
{
14695
tree arguments;
14696
tree saved_scope;
14697
tree saved_qualifying_scope;
14698
tree saved_object_scope;
14699
bool saved_greater_than_is_operator_p;
14700
14701
/*
[temp.names]
14702
14703
When
parsing a template-id, the first non-nested `>' is taken as
14704
the
end of the template-argument-list rather than a greater-than
14705
operator.
*/
14706
saved_greater_than_is_operator_p
14707
=
parser->greater_than_is_operator_p;
14708
parser->greater_than_is_operator_p =
false;
14709
/*
Parsing the argument list may modify SCOPE, so we save it
14710
here.
*/
14711
saved_scope = parser->scope;
14712
saved_qualifying_scope =
parser->qualifying_scope;
14713
saved_object_scope =
parser->object_scope;
14714
/*
Parse the template-argument-list itself.
*/
14715
if (cp_lexer_next_token_is
(parser->lexer,
CPP_GREATER))
14716
arguments = NULL_TREE;
14717
else
14718
arguments = cp_parser_template_argument_list
(parser);
14719
/*
Look for the `>' that ends the template-argument-list. If we find
14720
a
'>>' instead, it's probably just a typo.
*/
14721
if (cp_lexer_next_token_is
(parser->lexer,
CPP_RSHIFT))
14722
{
14723
if
(!saved_greater_than_is_operator_p)
14724
{
14725
/* If we're in a
nested template argument list, the '>>' has to be
14726
a
typo for '> >'. We emit the error
message, but we continue
14727
parsing and we push a '>' as next
token, so that the argument
14728
list will be parsed correctly..
*/
14729
cp_token* token;
14730
error ("`>>'
should be `> >' within a nested template argument list");
14731
token = cp_lexer_peek_token
(parser->lexer);
14732
token->type = CPP_GREATER;
14733
}
14734
else
14735
{
14736
/*
If this is not a nested template argument list, the '>>' is
14737
a
typo for '>'. Emit an error message and
continue.
*/
14738
error ("spurious
`>>', use `>' to terminate a template argument list");
14739
cp_lexer_consume_token
(parser->lexer);
14740
}
14741
}
14742
else
14743
cp_parser_skip_until_found
(parser,
CPP_GREATER, "`>'");
14744
/*
The `>' token might be a greater-than operator again now.
*/
14745
parser->greater_than_is_operator_p
14746
=
saved_greater_than_is_operator_p;
14747
/* Restore the SAVED_SCOPE.
*/
14748
parser->scope =
saved_scope;
14749
parser->qualifying_scope
= saved_qualifying_scope;
14750
parser->object_scope =
saved_object_scope;
14751
14752
return
arguments;
14753
}
parser
的
in_template_argument_list_p
域如果为
true
表示我们正在模板实参列表中。因此我们首先需要缓存这个域的内容,并在解析实参列表之前临时将其设为
true
。
8265
static
tree
8266
cp_parser_template_argument_list
(cp_parser* parser)
in
parser.c
8267
{
8268
tree fixed_args[10];
8269
unsigned n_args = 0;
8270
unsigned alloced = 10;
8271
tree *arg_ary = fixed_args;
8272
tree vec;
8273
bool saved_in_template_argument_list_p;
8274
8275
saved_in_template_argument_list_p =
parser->in_template_argument_list_p;
8276
parser->in_template_argument_list_p =
true;
8277
do
8278
{
8279
tree argument;
8280
8281
if (n_args)
8282
/* Consume the
comma.
*/
8283
cp_lexer_consume_token
(parser->lexer);
8284
8285
/* Parse the
template-argument.
*/
8286
argument =
cp_parser_template_argument
(parser);
8287
if (n_args == alloced)
8288
{
8289
alloced *= 2;
8290
8291
if (arg_ary == fixed_args)
8292
{
8293
arg_ary = xmalloc (sizeof
(tree) * alloced);
8294
memcpy (arg_ary, fixed_args, sizeof
(tree) * n_args);
8295
}
8296
else
8297
arg_ary = xrealloc (arg_ary, sizeof
(tree) * alloced);
8298
}
8299
arg_ary[n_args++] = argument;
8300
}
8301
while
(cp_lexer_next_token_is
(parser->lexer,
CPP_COMMA));
8302
8303
vec = make_tree_vec (n_args);
8304
8305
while
(n_args--)
8306
TREE_VEC_ELT (vec, n_args) =
arg_ary[n_args];
8307
8308
if (arg_ary != fixed_args)
8309
free (arg_ary);
8310
parser->in_template_argument_list_p =
saved_in_template_argument_list_p;
8311
return
vec;
8312
}
在列表中的每个参数由
cp_parser_template_argument
解析。当所有的实参都被处理后,相应的所产生的节点被填充入
TREE_VEC
节点,并且该节点被作为返回值返回。
5.12.4.2.2.2.2.1.
解析实参
模板实参的语法树显示如下。
(
点此打开
)
根据【
8
】,在一个模板实参中,由
type-id
及
id-expression
所导致的二义性,按
type-id
来解析,而不考虑对应模板实参的形式(缺省模板实参不存在这样的二义性,因为
template-parameter
的形式确定了缺省
template-argument
必须是
type-id
)。
例如:
template
<class T>
void f();
template
<int I>
void f();
void g() {
f<int()>(); // int() is a type-id:
call the first f()
}
因此我们首先尝试
type-id
。
8330
static
tree
8331
cp_parser_template_argument
(cp_parser* parser)
in
parser.c
8332
{
8333
tree argument;
8334
bool template_p;
8335
bool address_p;
8336
bool maybe_type_id = false;
8337
cp_token *token;
8338
cp_id_kind idk;
8339
tree qualifying_class;
8340
8341
/* There's really
no way to know what we're looking at, so we just
8342
try each
alternative in order.
8343
8344
[temp.arg]
8345
8346
In
a template-argument, an ambiguity between a
type-id and an
8347
expression is
resolved to a type-id, regardless of the form of
8348
the
corresponding template-parameter.
8349
8350
Therefore, we try
a type-id first.
*/
8351
cp_parser_parse_tentatively
(parser);
8352
argument =
cp_parser_type_id
(parser);
8353
/* If there was no
error parsing the type-id but the next token is a '>>',
8354
we probably found
a typo for '> >'. But there are type-id which are
8355
also valid
expressions. For instance:
8356
8357
struct X { int operator >> (int); };
8358
template <int V> struct Foo {};
8359
Foo<X () >> 5> r;
8360
8361
Here 'X()' is a
valid type-id of a function type, but the user just
8362
wanted to write
the expression "X() >> 5". Thus, we remember that we
8363
found a valid
type-id, but we still try to parse the argument as an
8364
expression to see
what happens.
*/
8365
if (!cp_parser_error_occurred (parser)
8366
&& cp_lexer_next_token_is
(parser->lexer,
CPP_RSHIFT))
8367
{
8368
maybe_type_id = true;
8369
cp_parser_abort_tentative_parse (parser);
8370
}
8371
else
8372
{
8373
/* If the next
token isn't a `,' or a `>', then this argument wasn't
8374
really finished.
This means that the argument is not a valid
8375
type-id.
*/
8376
if
(!cp_parser_next_token_ends_template_argument_p (parser))
8377
cp_parser_error (parser, "expected
template-argument");
8378
/* If that
worked, we're done.
*/
8379
if (cp_parser_parse_definitely
(parser))
8380
return
argument;
8381
}
这里有一个棘手的情形需要小心处理。考虑在上面注释中给出的例子(这个例子不能通过编译,但不是因为
>>
):
struct
X { int operator
>> (int); };
template
<int V> struct
Foo {};
Foo<X() >> 5> r;
“
X()
”是一个
type-id
的实例,但“
X() >> 5
”则是移位表达式的实例(这是
assignment-expression
的一个变形,其中“
X()
”是一个
postfix-expression
)。因为解析器要尽可能多地在一次中解析符号,它将把该字符串解析为移位表达式。然而由于失误,程序员也可能将“
> >
”写作“
>>
”,而把
type-id
从解析器的角度伸展为移位表达式。因此当成功解析一个后跟“
>>
”的
type-id
时,需要记住这个可能性,并且接着尝试按移位表达式来解析(此时,模板参数是非类型的)。细节在下面
assignment-expression
的情况一节。
5.12.4.2.2.2.2.1.1.
type-id
的情形
从其语法树,可以看到
type-id
包含了
type-specifier-seq
及可选的
abstract- declarator
。在经过解析之后,这些部分被包含在一个
TREE_LIST
节点,在其中,
type-specifier-seq
在
purpose
域,而
abstract-declarator
在
value
域中。
10924
static
tree
10925
cp_parser_type_id
(cp_parser* parser)
in
parser.c
10926
{
10927
tree type_specifier_seq;
10928
tree abstract_declarator;
10929
10930
/*
Parse the type-specifier-seq.
*/
10931
type_specifier_seq
10932
=
cp_parser_type_specifier_seq
(parser);
10933
if (type_specifier_seq ==
error_mark_node)
10934
return
error_mark_node;
10935
10936
/*
There might or might not be an abstract declarator.
*/
10937
cp_parser_parse_tentatively
(parser);
10938
/*
Look for the declarator.
*/
10939
abstract_declarator
10940
=
cp_parser_declarator
(parser, CP_PARSER_DECLARATOR_ABSTRACT, NULL,
10941
/*parenthesized_p=*/
NULL,
10942
/*member_p=*/
false);
10943
/*
Check to see if there really was a declarator.
*/
10944
if (!cp_parser_parse_definitely
(parser))
10945
abstract_declarator =
NULL_TREE;
10946
10947
return
groktypename
(build_tree_list
(type_specifier_seq,
10948
abstract_declarator));
10949
}
type-specifier-seq
的语法给出如下。
type-specifier-seq
├
type-specifier type-specifier-seq
[opt]
GUN Ext
Ⅼ
attributes type-specifier-seq
10964
static
tree
10965
cp_parser_type_specifier_seq
(cp_parser* parser)
in
parser.c
10966
{
10967
bool seen_type_specifier =
false;
10968
tree type_specifier_seq =
NULL_TREE;
10969
10970
/*
Parse the type-specifiers and attributes.
*/
10971
while
(true)
10972
{
10973
tree type_specifier;
10974
10975
/*
Check for attributes first.
*/
10976
if (cp_lexer_next_token_is_keyword
(parser->lexer, RID_ATTRIBUTE))
10977
{
10978
type_specifier_seq =
tree_cons
(cp_parser_attributes_opt (parser),
10979
NULL_TREE,
10980
type_specifier_seq);
10981
continue
;
10982
}
10983
10984
/* After the first type-specifier, others are
optional.
*/
10985
if (seen_type_specifier)
10986
cp_parser_parse_tentatively
(parser);
10987
/* Look for the type-specifier.
*/
10988
type_specifier
= cp_parser_type_specifier
(parser,
10989
CP_PARSER_FLAGS_NONE,
10990
/*is_friend=*/
false,
10991
/*is_declaration=*/
false,
10992
NULL,
10993
NULL);
10994
/*
If the first type-specifier could not be found, this is not a
10995
type-specifier-seq at all.
*/
10996
if (!seen_type_specifier
&& type_specifier == error_mark_node)
10997
return
error_mark_node;
10998
/*
If subsequent type-specifiers could not be found, the
10999
type-specifier-seq is complete.
*/
11000
else if
(seen_type_specifier && !cp_parser_parse_definitely
(parser))
11001
break
;
11002
11003
/*
Add the new type-specifier to the list.
*/
11004
type_specifier_seq
11005
= tree_cons
(NULL_TREE, type_specifier, type_specifier_seq);
11006
seen_type_specifier =
true;
11007
}
11008
11009
/*
We built up the list in reverse order.
*/
11010
return
nreverse (type_specifier_seq);
11011
}
函数
cp_parser_declarator
在这里被递归调用,不过仅是为了
abstract-declarator
。因为
type-id
在语义上是一个对象或函数的声明,其类型忽略对象或函数的名字,这个声明是一个类型的名字。根据解析的结果,应该由
groktypename
构建
*_TYPE
节点。
3640
tree
3641
groktypename
(tree typename)
in decl.c
3642
{
3643
tree specs, attrs;
3644
tree type;
3645
if (TREE_CODE (typename) != TREE_LIST)
3646
return
typename;
3647
split_specs_attrs
(TREE_PURPOSE (typename), &specs, &attrs);
3648
type = grokdeclarator
(TREE_VALUE (typename), specs,
3649
TYPENAME, 0, &attrs);
3650
if (attrs)
3651
cplus_decl_attributes
(&type, attrs, 0);
3652
return
type;
3653
}
上面,属性及
type-specifier
被串接入同一个链表,需要把这个链表分成
2
个链表。下面的参数
declspecs
将持有
type-specifier-seq
部分,而
prefix_attributes
将保存属性链表如果出现的话。在
340
行的条件找出了一个整型常量,如‘
5
’等。而如果
spec_attrs
不是
tree_list
,则意味着没有属性。
334
void
335
split_specs_attrs
(tree specs_attrs, tree *declspecs, tree *prefix_attributes)
in attribs.c
336
{
337
tree t, s, a, next, specs, attrs;
338
339
/* This can happen after an __extension__ in
pedantic mode.
*/
340
if (specs_attrs != NULL_TREE
341
&& TREE_CODE (specs_attrs) == INTEGER_CST)
342
{
343
*declspecs = NULL_TREE;
344
*prefix_attributes = NULL_TREE;
345
return
;
346
}
347
348
/* This can happen in c++ (eg: decl: typespec
initdecls ';').
*/
349
if (specs_attrs != NULL_TREE
350
&& TREE_CODE (specs_attrs) != TREE_LIST)
351
{
352
*declspecs = specs_attrs;
353
*prefix_attributes = NULL_TREE;
354
return
;
355
}
356
357
/* Remember to keep the lists in the same
order, element-wise.
*/
358
359
specs = s = NULL_TREE;
360
attrs = a = NULL_TREE;
361
for
(t = specs_attrs; t; t = next)
362
{
363
next = TREE_CHAIN (t);
364
/* Declspecs have a non-NULL TREE_VALUE.
*/
365
if (TREE_VALUE (t) != NULL_TREE)
366
{
367
if (specs == NULL_TREE)
368
specs = s = t;
369
else
370
{
371
TREE_CHAIN (s) = t;
372
s = t;
373
}
374
}
375
/* The TREE_PURPOSE may also be empty in the
case of
376
__attribute__(()).
*/
377
else if (TREE_PURPOSE (t) != NULL_TREE)
378
{
379
if (attrs == NULL_TREE)
380
attrs = a = TREE_PURPOSE (t);
381
else
382
{
383
TREE_CHAIN (a) = TREE_PURPOSE (t);
384
a = TREE_PURPOSE (t);
385
}
386
/* More
attrs can be linked here, move A to the end.
*/
387
while
(TREE_CHAIN (a) != NULL_TREE)
388
a = TREE_CHAIN (a);
389
}
390
}
391
392
/* Terminate the lists.
*/
393
if (s != NULL_TREE)
394
TREE_CHAIN (s) = NULL_TREE;
395
if (a != NULL_TREE)
396
TREE_CHAIN (a) = NULL_TREE;
397
398
/* All done.
*/
399
*declspecs = specs;
400
*prefix_attributes = attrs;
401
}
对于
type-specifier-seq
,此处,可以看到
type-specifiers
总是通过
tree_list
的
value
域串接起来,而
abstract-declarator
连同其属性总是由
purpose
域来串接。然后函数
grokdeclarator
为该对象或函数的类型返回相应的
TYPE_DECL
节点。在前面的章节中,我们已经看过这个函数的几个例子,因此这里我们跳过它。接下来
type-id
的属性将由
cplus_decl_attributes
安装入这个
TYPE_DECL
节点。
在
4.3.1.7.5.6.5.
处理内建函数的属性
一节中,我们已经看到前端使用数据结构
attribute_spec
来描述每个属性。表
common_attribute_table
,
attribute_table
,
format_attribute_table
用于
C++
,而
format_attribute_table
用于
x86
(目标机器)。它们预定义了可以在语言中及指定平台上使用的所有属性。
1102
void
1103
cplus_decl_attributes
(tree *decl, tree
attributes, int flags)
in
decl2.c
1104
{
1105
if (*decl == NULL_TREE || *decl ==
void_type_node)
1106
return
;
1107
1108
if (TREE_CODE (*decl) == TEMPLATE_DECL)
1109
decl = &DECL_TEMPLATE_RESULT (*decl);
1110
1111
decl_attributes
(decl, attributes, flags);
1112
1113
if (TREE_CODE (*decl) == TYPE_DECL)
1114
SET_IDENTIFIER_TYPE_VALUE
(DECL_NAME (*decl), TREE_TYPE (*decl));
1115
}
当调用
decl_attributes
时,我们可以通过向参数
flags
设置特定的
enum
attribute_flags
的值,来指定要安装的属性,而没有安装的属性将通过一个链表返回。这里我们把
flags
指定为
0
,表示安装所有提供的属性。
在
4.3.1.7.5.6.5.
处理内建函数的属性
一节中,我们已经看到绝大多数属性具有关联的处理句柄,这些句柄将适当地修改树节点。除此之外,已应用的属性通过宏
*_ATTRIBUTES
链接入树节点的
attributes
域。这些宏同时也作为一个快速的方法来查看在该节点上应用了哪些属性。
5.12.4.2.2.2.2.1.2.
id-expression
的情形
如果这不是
type-id
,那么我们按
id-expression
重新解析符号。
cp_parser_template_argument
(continue)
8382
/* We're still not
sure what the argument will be.
*/
8383
cp_parser_parse_tentatively
(parser);
8384
/* Try a
template.
*/
8385
argument =
cp_parser_id_expression
(parser,
8386
/*template_keyword_p=*/
false,
8387
/*check_dependency_p=*/
true,
8388
&template_p,
8389
/*declarator_p=*/
false);
8390
/* If the next
token isn't a `,' or a `>', then this argument wasn't
8391
really
finished.
*/
8392
if
(!cp_parser_next_token_ends_template_argument_p (parser))
8393
cp_parser_error (parser, "expected
template-argument");
8394
if (!cp_parser_error_occurred (parser))
8395
{
8396
/* Figure out
what is being referred to. If the id-expression
8397
was for a class template specialization, then
we will have a
8398
TYPE_DECL at this point. There is no need to
do name lookup
8399
at this point in that case.
*/
8400
if (TREE_CODE (argument) != TYPE_DECL)
8401
argument = cp_parser_lookup_name
(parser, argument,
8402
/*is_type=*/
false,
8403
/*is_template=*/
template_p,
8404
/*is_namespace=*/
false,
8405
/*check_dependency=*/
true);
8406
if (TREE_CODE (argument) != TEMPLATE_DECL
8407
&& TREE_CODE (argument) !=
UNBOUND_CLASS_TEMPLATE)
8408
cp_parser_error (parser, "expected
template-name");
8409
}
8410
if (cp_parser_parse_definitely
(parser))
8411
return
argument;
在
5.12.3.2.1.1.3.4.1.
解析声明符
一节中已经给出了一个
cp_parser_id_expression
的例子。如果查找的结果不是
TYPE_DECL
或
CPP_TEMPLATE_ID
,如果没有发生错误,它必须是一个标识符;那么这个名字将进一步被查找以找出关联的声明,就像
8401
行所作的那样。
5.12.4.2.2.2.2.1.3.
assignment-expression
的情形
如果我们按
type-id
解析成功,并且看到后面跟着“
>>
”,或者上面的尝试都失败了,该模板实参可能是
assignment-expression
的形式。在这个情形下,这个模板实参必须是非类型实参。根据
[3]
,非类型模板实参可以是:
—
一个具有整型或枚举类型的整形常量表达式;或者
—
一个非类型模板参数的名字;或者
—
表达为
&
id-expression
,其中
&
是可选的,如果该名字引用一个函数或数组,具有外部链接性的对象或函数的地址,包括函数模板及函数
template-id
,但不包括的非静态类成员;或者对应的模板参数是一个引用,具有外部链接性的对象或函数;或者
—
指向一个成员的指针
cp_parser_template_argument (continue)
8412
/* It must be a
non-type argument. There permitted cases are given
8413
in
[temp.arg.nontype]:
8414
8415
-- an integral
constant-expression of integral or enumeration
8416
type; or
8417
8418
-- the name of a
non-type template-parameter; or
8419
8420
-- the name of an
object or function with external linkage...
8421
8422
-- the address of
an object or function with external linkage...
8423
8424
-- a pointer to
member...
*/
8425
/* Look for a non-type template
parameter.
*/
8426
if (cp_lexer_next_token_is
(parser->lexer, CPP_NAME))
8427
{
8428
cp_parser_parse_tentatively
(parser);
8429
argument = cp_parser_primary_expression
(parser,
8430
&idk,
8431
&qualifying_class);
8432
if (TREE_CODE (argument) !=
TEMPLATE_PARM_INDEX
8433
||
!cp_parser_next_token_ends_template_argument_p (parser))
8434
cp_parser_simulate_error (parser);
8435
if (cp_parser_parse_definitely
(parser))
8436
return
argument;
8437
}
在按
assignment-expression
解析该模板实参期间,如果我们看到第一个符号是一个标识符,从图形:
语句语法树
,可以看到它一定是
assignment-expression
语法树中
primary-expression
部分的头部。如果
primary-expression
能被成功解析,我们就做完了。
否则,就检查在
primary-expression
之前是否有引导的
&
。这样形式的实参对应于后
2
种形式的非类型实参(记住该实参必须是编译时常量,对于指向成员的指针,它必须像:“
&A::f
”)。同样如果模板实参可以被解析为
primary-expression
,我们就完成了。我们不进入
primary-expression
的处理细节。在
5.12.4.1.2.
非类型参数
一节中可以找到一些相关的解释。
cp_parser_template_argument
(continue)
8438
/* If the next
token is "&", the argument must be the address of an
8439
object or
function with external linkage.
*/
8440
address_p = cp_lexer_next_token_is
(parser->lexer, CPP_AND);
8441
if (address_p)
8442
cp_lexer_consume_token
(parser->lexer);
8443
/* See if we might
have an id-expression.
*/
8444
token = cp_lexer_peek_token
(parser->lexer);
8445
if (token->type == CPP_NAME
8446
|| token->keyword == RID_OPERATOR
8447
|| token->type == CPP_SCOPE
8448
|| token->type == CPP_TEMPLATE_ID
8449
|| token->type ==
CPP_NESTED_NAME_SPECIFIER)
8450
{
8451
cp_parser_parse_tentatively
(parser);
8452
argument = cp_parser_primary_expression
(parser,
8453
&idk,
8454
&qualifying_class);
8455
if (cp_parser_error_occurred (parser)
8456
|| !cp_parser_next_token_ends_template_argument_p
(parser))
8457
cp_parser_abort_tentative_parse (parser);
8458
else
8459
{
8460
if (qualifying_class)
8461
argument = finish_qualified_id_expr
(qualifying_class,
8462
argument,
8463
/*done=*/
true,
8464
address_p);
8465
if (TREE_CODE (argument) == VAR_DECL)
8466
{
8467
/* A variable
without external linkage might still be a
8468
valid constant-expression, so no error is
issued here
8469
if the external-linkage check fails.
*/
8470
if (!DECL_EXTERNAL_LINKAGE_P
(argument))
8471
cp_parser_simulate_error (parser);
8472
}
8473
else if (is_overloaded_fn
(argument))
8474
/* All
overloaded functions are allowed; if the external
8475
linkage test does not pass, an error
will be issued
8476
later.
*/
8477
;
8478
else if (address_p
8479
&& (TREE_CODE (argument) ==
OFFSET_REF
8480
|| TREE_CODE (argument) ==
SCOPE_REF))
8481
/* A
pointer-to-member.
*/
8482
;
8483
else
8484
cp_parser_simulate_error (parser);
8485
8486
if (cp_parser_parse_definitely
(parser))
8487
{
8488
if (address_p)
8489
argument = build_x_unary_op
(ADDR_EXPR, argument);
8490
return
argument;
8491
}
8492
}
8493
}
8494
/* If the argument started with
"&", there are no other valid
8495
alternatives at
this point.
*/
8496
if (address_p)
8497
{
8498
cp_parser_error (parser, "invalid
non-type template argument");
8499
return
error_mark_node;
8500
}
上面
qualifying_class
由
cp_parser_primary_expression
设置,表示
pointer-to-member
中的限定类。如果设置了
qualifyng_class
,在
8461
行,
finish_qualified_id_expr
在
qualifying_class
的上下文查找
argument
,并为形如:“
A::f
”或“
a.*f
”的表达式构建相应的
OFFSET_REF
节点。然后在
8489
行,
build_x_unary_op
为形如:“
&A::f
”的表达式构建相应的
ADDR_EXPR
节点。
如果上面的尝试都失败,那么看一下
assignment-expression
的语法树,根据【
3
】的要求,非类型模板实参必须是常量表达式。在这个语法树中,第二及第三规则不是常量表达式;而且常量表达式(
constant-expression
)可直接降为条件表达式(
xxx? xxx: xxx
)。
assignment-expression
├
condition-expression
|
Ⅼ
condition-expression
├
logical-or-expression assignment-operator assignment-expression
Ⅼ
throw-expression
因此下一步我们尝试常量表达式。看到下面的
maybe_type_id
如果是
true
表示一开始按
type-id
来解析是成功的,并且其后跟着“
>>
”。因此如果
maybe_type_id
是
true
,意味着我们要尝试把模板实参按移位表达式来解析,它为常量表达式语法所涵盖。
cp_parser_template_argument
(continue)
8501
/* If the argument wasn't successfully parsed
as a type-id followed
8502
by '>>',
the argument can only be a constant expression now.
8503
Otherwise, we try
parsing the constant-expression tentatively,
8504
because the
argument could really be a type-id.
*/
8505
if (maybe_type_id)
8506
cp_parser_parse_tentatively
(parser);
8507
argument = cp_parser_constant_expression
(parser,
8508
/*allow_non_constant_p=*/
false,
8509
/*non_constant_p=*/
NULL);
8510
argument = fold_non_dependent_expr
(argument);
8511
if (!maybe_type_id)
8512
return
argument;
8513
if
(!cp_parser_next_token_ends_template_argument_p (parser))
8514
cp_parser_error (parser, "expected
template-argument");
8515
if (cp_parser_parse_definitely
(parser))
8516
return
argument;
8517
/* We did our best
to parse the argument as a non type-id, but that
8518
was the only
alternative that matched (albeit with a '>' after
8519
it). We can
assume it's just a typo from the user, and a
8520
diagnostic will
then be issued.
*/
8521
return
cp_parser_type_id
(parser);
8522
}
而如果
maybe_type_id
是
false
,这是我们最后的机会,返回这个结果,不检查是否发生错误(错误消息由处理函数产生)。否则,需要确认该移位表达式正确构成了实参——即在它之后是否跟着“
,
”或“
>
”(注意,如果错把正确的非类型实参给了类型参数,这里是无法查出的,但在后面的处理中会发现实参与参数类型的不匹配)。如果不能,重新按
type-id
来解析符号,因为很可能是误把“
> >
”写作“
>>
”,这样编译器可以给出更合理的错误信息(看回
cp_parser_enclosed_template_argument_list
,它还将处理额外的“
>>
”返回)。
解析实参列表
然后调用
cp_parser_enclosed_template_argument_list
来解析
template-id
中所包含的模板实参列表。在这个处理之前,
parser
的
greater_than_is_operator_p
域将被设置为
false
,因为从现在起进来的“
>
”将不被视为操作符。而在实参列表中输入的“
>>
”将被解析作“
>
”和“
>
”,例如,“
A<B<>> a
”,前端将把它视为“
A<B<> > a
”。看到解析器将尝试从这个错误恢复并继续前行,但不保证可以产生正确的代码,因为程序员在这里犯了错误,因此给出错误信息。
14692
static
tree
14693
cp_parser_enclosed_template_argument_list
(cp_parser* parser)
in
parser.c
14694
{
14695
tree arguments;
14696
tree saved_scope;
14697
tree saved_qualifying_scope;
14698
tree saved_object_scope;
14699
bool saved_greater_than_is_operator_p;
14700
14701
/*
[temp.names]
14702
14703
When
parsing a template-id, the first non-nested `>' is taken as
14704
the
end of the template-argument-list rather than a greater-than
14705
operator.
*/
14706
saved_greater_than_is_operator_p
14707
=
parser->greater_than_is_operator_p;
14708
parser->greater_than_is_operator_p =
false;
14709
/*
Parsing the argument list may modify SCOPE, so we save it
14710
here.
*/
14711
saved_scope = parser->scope;
14712
saved_qualifying_scope =
parser->qualifying_scope;
14713
saved_object_scope =
parser->object_scope;
14714
/*
Parse the template-argument-list itself.
*/
14715
if (cp_lexer_next_token_is
(parser->lexer,
CPP_GREATER))
14716
arguments = NULL_TREE;
14717
else
14718
arguments = cp_parser_template_argument_list
(parser);
14719
/*
Look for the `>' that ends the template-argument-list. If we find
14720
a
'>>' instead, it's probably just a typo.
*/
14721
if (cp_lexer_next_token_is
(parser->lexer,
CPP_RSHIFT))
14722
{
14723
if
(!saved_greater_than_is_operator_p)
14724
{
14725
/* If we're in a
nested template argument list, the '>>' has to be
14726
a
typo for '> >'. We emit the error
message, but we continue
14727
parsing and we push a '>' as next
token, so that the argument
14728
list will be parsed correctly..
*/
14729
cp_token* token;
14730
error ("`>>'
should be `> >' within a nested template argument list");
14731
token = cp_lexer_peek_token
(parser->lexer);
14732
token->type = CPP_GREATER;
14733
}
14734
else
14735
{
14736
/*
If this is not a nested template argument list, the '>>' is
14737
a
typo for '>'. Emit an error message and
continue.
*/
14738
error ("spurious
`>>', use `>' to terminate a template argument list");
14739
cp_lexer_consume_token
(parser->lexer);
14740
}
14741
}
14742
else
14743
cp_parser_skip_until_found
(parser,
CPP_GREATER, "`>'");
14744
/*
The `>' token might be a greater-than operator again now.
*/
14745
parser->greater_than_is_operator_p
14746
=
saved_greater_than_is_operator_p;
14747
/* Restore the SAVED_SCOPE.
*/
14748
parser->scope =
saved_scope;
14749
parser->qualifying_scope
= saved_qualifying_scope;
14750
parser->object_scope =
saved_object_scope;
14751
14752
return
arguments;
14753
}
parser
的
in_template_argument_list_p
域如果为
true
表示我们正在模板实参列表中。因此我们首先需要缓存这个域的内容,并在解析实参列表之前临时将其设为
true
。
8265
static
tree
8266
cp_parser_template_argument_list
(cp_parser* parser)
in
parser.c
8267
{
8268
tree fixed_args[10];
8269
unsigned n_args = 0;
8270
unsigned alloced = 10;
8271
tree *arg_ary = fixed_args;
8272
tree vec;
8273
bool saved_in_template_argument_list_p;
8274
8275
saved_in_template_argument_list_p =
parser->in_template_argument_list_p;
8276
parser->in_template_argument_list_p =
true;
8277
do
8278
{
8279
tree argument;
8280
8281
if (n_args)
8282
/* Consume the
comma.
*/
8283
cp_lexer_consume_token
(parser->lexer);
8284
8285
/* Parse the
template-argument.
*/
8286
argument =
cp_parser_template_argument
(parser);
8287
if (n_args == alloced)
8288
{
8289
alloced *= 2;
8290
8291
if (arg_ary == fixed_args)
8292
{
8293
arg_ary = xmalloc (sizeof
(tree) * alloced);
8294
memcpy (arg_ary, fixed_args, sizeof
(tree) * n_args);
8295
}
8296
else
8297
arg_ary = xrealloc (arg_ary, sizeof
(tree) * alloced);
8298
}
8299
arg_ary[n_args++] = argument;
8300
}
8301
while
(cp_lexer_next_token_is
(parser->lexer,
CPP_COMMA));
8302
8303
vec = make_tree_vec (n_args);
8304
8305
while
(n_args--)
8306
TREE_VEC_ELT (vec, n_args) =
arg_ary[n_args];
8307
8308
if (arg_ary != fixed_args)
8309
free (arg_ary);
8310
parser->in_template_argument_list_p =
saved_in_template_argument_list_p;
8311
return
vec;
8312
}
在列表中的每个参数由
cp_parser_template_argument
解析。当所有的实参都被处理后,相应的所产生的节点被填充入
TREE_VEC
节点,并且该节点被作为返回值返回。
5.12.4.2.2.2.2.1.
解析实参
模板实参的语法树显示如下。
(
点此打开
)
根据【
8
】,在一个模板实参中,由
type-id
及
id-expression
所导致的二义性,按
type-id
来解析,而不考虑对应模板实参的形式(缺省模板实参不存在这样的二义性,因为
template-parameter
的形式确定了缺省
template-argument
必须是
type-id
)。
例如:
template
<class T>
void f();
template
<int I>
void f();
void g() {
f<int()>(); // int() is a type-id:
call the first f()
}
因此我们首先尝试
type-id
。
8330
static
tree
8331
cp_parser_template_argument
(cp_parser* parser)
in
parser.c
8332
{
8333
tree argument;
8334
bool template_p;
8335
bool address_p;
8336
bool maybe_type_id = false;
8337
cp_token *token;
8338
cp_id_kind idk;
8339
tree qualifying_class;
8340
8341
/* There's really
no way to know what we're looking at, so we just
8342
try each
alternative in order.
8343
8344
[temp.arg]
8345
8346
In
a template-argument, an ambiguity between a
type-id and an
8347
expression is
resolved to a type-id, regardless of the form of
8348
the
corresponding template-parameter.
8349
8350
Therefore, we try
a type-id first.
*/
8351
cp_parser_parse_tentatively
(parser);
8352
argument =
cp_parser_type_id
(parser);
8353
/* If there was no
error parsing the type-id but the next token is a '>>',
8354
we probably found
a typo for '> >'. But there are type-id which are
8355
also valid
expressions. For instance:
8356
8357
struct X { int operator >> (int); };
8358
template <int V> struct Foo {};
8359
Foo<X () >> 5> r;
8360
8361
Here 'X()' is a
valid type-id of a function type, but the user just
8362
wanted to write
the expression "X() >> 5". Thus, we remember that we
8363
found a valid
type-id, but we still try to parse the argument as an
8364
expression to see
what happens.
*/
8365
if (!cp_parser_error_occurred (parser)
8366
&& cp_lexer_next_token_is
(parser->lexer,
CPP_RSHIFT))
8367
{
8368
maybe_type_id = true;
8369
cp_parser_abort_tentative_parse (parser);
8370
}
8371
else
8372
{
8373
/* If the next
token isn't a `,' or a `>', then this argument wasn't
8374
really finished.
This means that the argument is not a valid
8375
type-id.
*/
8376
if
(!cp_parser_next_token_ends_template_argument_p (parser))
8377
cp_parser_error (parser, "expected
template-argument");
8378
/* If that
worked, we're done.
*/
8379
if (cp_parser_parse_definitely
(parser))
8380
return
argument;
8381
}
这里有一个棘手的情形需要小心处理。考虑在上面注释中给出的例子(这个例子不能通过编译,但不是因为
>>
):
struct
X { int operator
>> (int); };
template
<int V> struct
Foo {};
Foo<X() >> 5> r;
“
X()
”是一个
type-id
的实例,但“
X() >> 5
”则是移位表达式的实例(这是
assignment-expression
的一个变形,其中“
X()
”是一个
postfix-expression
)。因为解析器要尽可能多地在一次中解析符号,它将把该字符串解析为移位表达式。然而由于失误,程序员也可能将“
> >
”写作“
>>
”,而把
type-id
从解析器的角度伸展为移位表达式。因此当成功解析一个后跟“
>>
”的
type-id
时,需要记住这个可能性,并且接着尝试按移位表达式来解析(此时,模板参数是非类型的)。细节在下面
assignment-expression
的情况一节。
5.12.4.2.2.2.2.1.1.
type-id
的情形
从其语法树,可以看到
type-id
包含了
type-specifier-seq
及可选的
abstract- declarator
。在经过解析之后,这些部分被包含在一个
TREE_LIST
节点,在其中,
type-specifier-seq
在
purpose
域,而
abstract-declarator
在
value
域中。
10924
static
tree
10925
cp_parser_type_id
(cp_parser* parser)
in
parser.c
10926
{
10927
tree type_specifier_seq;
10928
tree abstract_declarator;
10929
10930
/*
Parse the type-specifier-seq.
*/
10931
type_specifier_seq
10932
=
cp_parser_type_specifier_seq
(parser);
10933
if (type_specifier_seq ==
error_mark_node)
10934
return
error_mark_node;
10935
10936
/*
There might or might not be an abstract declarator.
*/
10937
cp_parser_parse_tentatively
(parser);
10938
/*
Look for the declarator.
*/
10939
abstract_declarator
10940
=
cp_parser_declarator
(parser, CP_PARSER_DECLARATOR_ABSTRACT, NULL,
10941
/*parenthesized_p=*/
NULL,
10942
/*member_p=*/
false);
10943
/*
Check to see if there really was a declarator.
*/
10944
if (!cp_parser_parse_definitely
(parser))
10945
abstract_declarator =
NULL_TREE;
10946
10947
return
groktypename
(build_tree_list
(type_specifier_seq,
10948
abstract_declarator));
10949
}
type-specifier-seq
的语法给出如下。
type-specifier-seq
├
type-specifier type-specifier-seq
[opt]
GUN Ext
Ⅼ
attributes type-specifier-seq
10964
static
tree
10965
cp_parser_type_specifier_seq
(cp_parser* parser)
in
parser.c
10966
{
10967
bool seen_type_specifier =
false;
10968
tree type_specifier_seq =
NULL_TREE;
10969
10970
/*
Parse the type-specifiers and attributes.
*/
10971
while
(true)
10972
{
10973
tree type_specifier;
10974
10975
/*
Check for attributes first.
*/
10976
if (cp_lexer_next_token_is_keyword
(parser->lexer, RID_ATTRIBUTE))
10977
{
10978
type_specifier_seq =
tree_cons
(cp_parser_attributes_opt (parser),
10979
NULL_TREE,
10980
type_specifier_seq);
10981
continue
;
10982
}
10983
10984
/* After the first type-specifier, others are
optional.
*/
10985
if (seen_type_specifier)
10986
cp_parser_parse_tentatively
(parser);
10987
/* Look for the type-specifier.
*/
10988
type_specifier
= cp_parser_type_specifier
(parser,
10989
CP_PARSER_FLAGS_NONE,
10990
/*is_friend=*/
false,
10991
/*is_declaration=*/
false,
10992
NULL,
10993
NULL);
10994
/*
If the first type-specifier could not be found, this is not a
10995
type-specifier-seq at all.
*/
10996
if (!seen_type_specifier
&& type_specifier == error_mark_node)
10997
return
error_mark_node;
10998
/*
If subsequent type-specifiers could not be found, the
10999
type-specifier-seq is complete.
*/
11000
else if
(seen_type_specifier && !cp_parser_parse_definitely
(parser))
11001
break
;
11002
11003
/*
Add the new type-specifier to the list.
*/
11004
type_specifier_seq
11005
= tree_cons
(NULL_TREE, type_specifier, type_specifier_seq);
11006
seen_type_specifier =
true;
11007
}
11008
11009
/*
We built up the list in reverse order.
*/
11010
return
nreverse (type_specifier_seq);
11011
}
函数
cp_parser_declarator
在这里被递归调用,不过仅是为了
abstract-declarator
。因为
type-id
在语义上是一个对象或函数的声明,其类型忽略对象或函数的名字,这个声明是一个类型的名字。根据解析的结果,应该由
groktypename
构建
*_TYPE
节点。
3640
tree
3641
groktypename
(tree typename)
in decl.c
3642
{
3643
tree specs, attrs;
3644
tree type;
3645
if (TREE_CODE (typename) != TREE_LIST)
3646
return
typename;
3647
split_specs_attrs
(TREE_PURPOSE (typename), &specs, &attrs);
3648
type = grokdeclarator
(TREE_VALUE (typename), specs,
3649
TYPENAME, 0, &attrs);
3650
if (attrs)
3651
cplus_decl_attributes
(&type, attrs, 0);
3652
return
type;
3653
}
上面,属性及
type-specifier
被串接入同一个链表,需要把这个链表分成
2
个链表。下面的参数
declspecs
将持有
type-specifier-seq
部分,而
prefix_attributes
将保存属性链表如果出现的话。在
340
行的条件找出了一个整型常量,如‘
5
’等。而如果
spec_attrs
不是
tree_list
,则意味着没有属性。
334
void
335
split_specs_attrs
(tree specs_attrs, tree *declspecs, tree *prefix_attributes)
in attribs.c
336
{
337
tree t, s, a, next, specs, attrs;
338
339
/* This can happen after an __extension__ in
pedantic mode.
*/
340
if (specs_attrs != NULL_TREE
341
&& TREE_CODE (specs_attrs) == INTEGER_CST)
342
{
343
*declspecs = NULL_TREE;
344
*prefix_attributes = NULL_TREE;
345
return
;
346
}
347
348
/* This can happen in c++ (eg: decl: typespec
initdecls ';').
*/
349
if (specs_attrs != NULL_TREE
350
&& TREE_CODE (specs_attrs) != TREE_LIST)
351
{
352
*declspecs = specs_attrs;
353
*prefix_attributes = NULL_TREE;
354
return
;
355
}
356
357
/* Remember to keep the lists in the same
order, element-wise.
*/
358
359
specs = s = NULL_TREE;
360
attrs = a = NULL_TREE;
361
for
(t = specs_attrs; t; t = next)
362
{
363
next = TREE_CHAIN (t);
364
/* Declspecs have a non-NULL TREE_VALUE.
*/
365
if (TREE_VALUE (t) != NULL_TREE)
366
{
367
if (specs == NULL_TREE)
368
specs = s = t;
369
else
370
{
371
TREE_CHAIN (s) = t;
372
s = t;
373
}
374
}
375
/* The TREE_PURPOSE may also be empty in the
case of
376
__attribute__(()).
*/
377
else if (TREE_PURPOSE (t) != NULL_TREE)
378
{
379
if (attrs == NULL_TREE)
380
attrs = a = TREE_PURPOSE (t);
381
else
382
{
383
TREE_CHAIN (a) = TREE_PURPOSE (t);
384
a = TREE_PURPOSE (t);
385
}
386
/* More
attrs can be linked here, move A to the end.
*/
387
while
(TREE_CHAIN (a) != NULL_TREE)
388
a = TREE_CHAIN (a);
389
}
390
}
391
392
/* Terminate the lists.
*/
393
if (s != NULL_TREE)
394
TREE_CHAIN (s) = NULL_TREE;
395
if (a != NULL_TREE)
396
TREE_CHAIN (a) = NULL_TREE;
397
398
/* All done.
*/
399
*declspecs = specs;
400
*prefix_attributes = attrs;
401
}
对于
type-specifier-seq
,此处,可以看到
type-specifiers
总是通过
tree_list
的
value
域串接起来,而
abstract-declarator
连同其属性总是由
purpose
域来串接。然后函数
grokdeclarator
为该对象或函数的类型返回相应的
TYPE_DECL
节点。在前面的章节中,我们已经看过这个函数的几个例子,因此这里我们跳过它。接下来
type-id
的属性将由
cplus_decl_attributes
安装入这个
TYPE_DECL
节点。
在
4.3.1.7.5.6.5.
处理内建函数的属性
一节中,我们已经看到前端使用数据结构
attribute_spec
来描述每个属性。表
common_attribute_table
,
attribute_table
,
format_attribute_table
用于
C++
,而
format_attribute_table
用于
x86
(目标机器)。它们预定义了可以在语言中及指定平台上使用的所有属性。
1102
void
1103
cplus_decl_attributes
(tree *decl, tree
attributes, int flags)
in
decl2.c
1104
{
1105
if (*decl == NULL_TREE || *decl ==
void_type_node)
1106
return
;
1107
1108
if (TREE_CODE (*decl) == TEMPLATE_DECL)
1109
decl = &DECL_TEMPLATE_RESULT (*decl);
1110
1111
decl_attributes
(decl, attributes, flags);
1112
1113
if (TREE_CODE (*decl) == TYPE_DECL)
1114
SET_IDENTIFIER_TYPE_VALUE
(DECL_NAME (*decl), TREE_TYPE (*decl));
1115
}
当调用
decl_attributes
时,我们可以通过向参数
flags
设置特定的
enum
attribute_flags
的值,来指定要安装的属性,而没有安装的属性将通过一个链表返回。这里我们把
flags
指定为
0
,表示安装所有提供的属性。
在
4.3.1.7.5.6.5.
处理内建函数的属性
一节中,我们已经看到绝大多数属性具有关联的处理句柄,这些句柄将适当地修改树节点。除此之外,已应用的属性通过宏
*_ATTRIBUTES
链接入树节点的
attributes
域。这些宏同时也作为一个快速的方法来查看在该节点上应用了哪些属性。
5.12.4.2.2.2.2.1.2.
id-expression
的情形
如果这不是
type-id
,那么我们按
id-expression
重新解析符号。
cp_parser_template_argument
(continue)
8382
/* We're still not
sure what the argument will be.
*/
8383
cp_parser_parse_tentatively
(parser);
8384
/* Try a
template.
*/
8385
argument =
cp_parser_id_expression
(parser,
8386
/*template_keyword_p=*/
false,
8387
/*check_dependency_p=*/
true,
8388
&template_p,
8389
/*declarator_p=*/
false);
8390
/* If the next
token isn't a `,' or a `>', then this argument wasn't
8391
really
finished.
*/
8392
if
(!cp_parser_next_token_ends_template_argument_p (parser))
8393
cp_parser_error (parser, "expected
template-argument");
8394
if (!cp_parser_error_occurred (parser))
8395
{
8396
/* Figure out
what is being referred to. If the id-expression
8397
was for a class template specialization, then
we will have a
8398
TYPE_DECL at this point. There is no need to
do name lookup
8399
at this point in that case.
*/
8400
if (TREE_CODE (argument) != TYPE_DECL)
8401
argument = cp_parser_lookup_name
(parser, argument,
8402
/*is_type=*/
false,
8403
/*is_template=*/
template_p,
8404
/*is_namespace=*/
false,
8405
/*check_dependency=*/
true);
8406
if (TREE_CODE (argument) != TEMPLATE_DECL
8407
&& TREE_CODE (argument) !=
UNBOUND_CLASS_TEMPLATE)
8408
cp_parser_error (parser, "expected
template-name");
8409
}
8410
if (cp_parser_parse_definitely
(parser))
8411
return
argument;
在
5.12.3.2.1.1.3.4.1.
解析声明符
一节中已经给出了一个
cp_parser_id_expression
的例子。如果查找的结果不是
TYPE_DECL
或
CPP_TEMPLATE_ID
,如果没有发生错误,它必须是一个标识符;那么这个名字将进一步被查找以找出关联的声明,就像
8401
行所作的那样。
5.12.4.2.2.2.2.1.3.
assignment-expression
的情形
如果我们按
type-id
解析成功,并且看到后面跟着“
>>
”,或者上面的尝试都失败了,该模板实参可能是
assignment-expression
的形式。在这个情形下,这个模板实参必须是非类型实参。根据
[3]
,非类型模板实参可以是:
—
一个具有整型或枚举类型的整形常量表达式;或者
—
一个非类型模板参数的名字;或者
—
表达为
&
id-expression
,其中
&
是可选的,如果该名字引用一个函数或数组,具有外部链接性的对象或函数的地址,包括函数模板及函数
template-id
,但不包括的非静态类成员;或者对应的模板参数是一个引用,具有外部链接性的对象或函数;或者
—
指向一个成员的指针
cp_parser_template_argument (continue)
8412
/* It must be a
non-type argument. There permitted cases are given
8413
in
[temp.arg.nontype]:
8414
8415
-- an integral
constant-expression of integral or enumeration
8416
type; or
8417
8418
-- the name of a
non-type template-parameter; or
8419
8420
-- the name of an
object or function with external linkage...
8421
8422
-- the address of
an object or function with external linkage...
8423
8424
-- a pointer to
member...
*/
8425
/* Look for a non-type template
parameter.
*/
8426
if (cp_lexer_next_token_is
(parser->lexer, CPP_NAME))
8427
{
8428
cp_parser_parse_tentatively
(parser);
8429
argument = cp_parser_primary_expression
(parser,
8430
&idk,
8431
&qualifying_class);
8432
if (TREE_CODE (argument) !=
TEMPLATE_PARM_INDEX
8433
||
!cp_parser_next_token_ends_template_argument_p (parser))
8434
cp_parser_simulate_error (parser);
8435
if (cp_parser_parse_definitely
(parser))
8436
return
argument;
8437
}
在按
assignment-expression
解析该模板实参期间,如果我们看到第一个符号是一个标识符,从图形:
语句语法树
,可以看到它一定是
assignment-expression
语法树中
primary-expression
部分的头部。如果
primary-expression
能被成功解析,我们就做完了。
否则,就检查在
primary-expression
之前是否有引导的
&
。这样形式的实参对应于后
2
种形式的非类型实参(记住该实参必须是编译时常量,对于指向成员的指针,它必须像:“
&A::f
”)。同样如果模板实参可以被解析为
primary-expression
,我们就完成了。我们不进入
primary-expression
的处理细节。在
5.12.4.1.2.
非类型参数
一节中可以找到一些相关的解释。
cp_parser_template_argument
(continue)
8438
/* If the next
token is "&", the argument must be the address of an
8439
object or
function with external linkage.
*/
8440
address_p = cp_lexer_next_token_is
(parser->lexer, CPP_AND);
8441
if (address_p)
8442
cp_lexer_consume_token
(parser->lexer);
8443
/* See if we might
have an id-expression.
*/
8444
token = cp_lexer_peek_token
(parser->lexer);
8445
if (token->type == CPP_NAME
8446
|| token->keyword == RID_OPERATOR
8447
|| token->type == CPP_SCOPE
8448
|| token->type == CPP_TEMPLATE_ID
8449
|| token->type ==
CPP_NESTED_NAME_SPECIFIER)
8450
{
8451
cp_parser_parse_tentatively
(parser);
8452
argument = cp_parser_primary_expression
(parser,
8453
&idk,
8454
&qualifying_class);
8455
if (cp_parser_error_occurred (parser)
8456
|| !cp_parser_next_token_ends_template_argument_p
(parser))
8457
cp_parser_abort_tentative_parse (parser);
8458
else
8459
{
8460
if (qualifying_class)
8461
argument = finish_qualified_id_expr
(qualifying_class,
8462
argument,
8463
/*done=*/
true,
8464
address_p);
8465
if (TREE_CODE (argument) == VAR_DECL)
8466
{
8467
/* A variable
without external linkage might still be a
8468
valid constant-expression, so no error is
issued here
8469
if the external-linkage check fails.
*/
8470
if (!DECL_EXTERNAL_LINKAGE_P
(argument))
8471
cp_parser_simulate_error (parser);
8472
}
8473
else if (is_overloaded_fn
(argument))
8474
/* All
overloaded functions are allowed; if the external
8475
linkage test does not pass, an error
will be issued
8476
later.
*/
8477
;
8478
else if (address_p
8479
&& (TREE_CODE (argument) ==
OFFSET_REF
8480
|| TREE_CODE (argument) ==
SCOPE_REF))
8481
/* A
pointer-to-member.
*/
8482
;
8483
else
8484
cp_parser_simulate_error (parser);
8485
8486
if (cp_parser_parse_definitely
(parser))
8487
{
8488
if (address_p)
8489
argument = build_x_unary_op
(ADDR_EXPR, argument);
8490
return
argument;
8491
}
8492
}
8493
}
8494
/* If the argument started with
"&", there are no other valid
8495
alternatives at
this point.
*/
8496
if (address_p)
8497
{
8498
cp_parser_error (parser, "invalid
non-type template argument");
8499
return
error_mark_node;
8500
}
上面
qualifying_class
由
cp_parser_primary_expression
设置,表示
pointer-to-member
中的限定类。如果设置了
qualifyng_class
,在
8461
行,
finish_qualified_id_expr
在
qualifying_class
的上下文查找
argument
,并为形如:“
A::f
”或“
a.*f
”的表达式构建相应的
OFFSET_REF
节点。然后在
8489
行,
build_x_unary_op
为形如:“
&A::f
”的表达式构建相应的
ADDR_EXPR
节点。
如果上面的尝试都失败,那么看一下
assignment-expression
的语法树,根据【
3
】的要求,非类型模板实参必须是常量表达式。在这个语法树中,第二及第三规则不是常量表达式;而且常量表达式(
constant-expression
)可直接降为条件表达式(
xxx? xxx: xxx
)。
assignment-expression
├
condition-expression
|
Ⅼ
condition-expression
├
logical-or-expression assignment-operator assignment-expression
Ⅼ
throw-expression
因此下一步我们尝试常量表达式。看到下面的
maybe_type_id
如果是
true
表示一开始按
type-id
来解析是成功的,并且其后跟着“
>>
”。因此如果
maybe_type_id
是
true
,意味着我们要尝试把模板实参按移位表达式来解析,它为常量表达式语法所涵盖。
cp_parser_template_argument
(continue)
8501
/* If the argument wasn't successfully parsed
as a type-id followed
8502
by '>>',
the argument can only be a constant expression now.
8503
Otherwise, we try
parsing the constant-expression tentatively,
8504
because the
argument could really be a type-id.
*/
8505
if (maybe_type_id)
8506
cp_parser_parse_tentatively
(parser);
8507
argument = cp_parser_constant_expression
(parser,
8508
/*allow_non_constant_p=*/
false,
8509
/*non_constant_p=*/
NULL);
8510
argument = fold_non_dependent_expr
(argument);
8511
if (!maybe_type_id)
8512
return
argument;
8513
if
(!cp_parser_next_token_ends_template_argument_p (parser))
8514
cp_parser_error (parser, "expected
template-argument");
8515
if (cp_parser_parse_definitely
(parser))
8516
return
argument;
8517
/* We did our best
to parse the argument as a non type-id, but that
8518
was the only
alternative that matched (albeit with a '>' after
8519
it). We can
assume it's just a typo from the user, and a
8520
diagnostic will
then be issued.
*/
8521
return
cp_parser_type_id
(parser);
8522
}
而如果
maybe_type_id
是
false
,这是我们最后的机会,返回这个结果,不检查是否发生错误(错误消息由处理函数产生)。否则,需要确认该移位表达式正确构成了实参——即在它之后是否跟着“
,
”或“
>
”(注意,如果错把正确的非类型实参给了类型参数,这里是无法查出的,但在后面的处理中会发现实参与参数类型的不匹配)。如果不能,重新按
type-id
来解析符号,因为很可能是误把“
> >
”写作“
>>
”,这样编译器可以给出更合理的错误信息(看回
cp_parser_enclosed_template_argument_list
,它还将处理额外的“
>>
”返回)。
相关文章推荐
- GCC-3.4.6源代码学习笔记(161)
- GCC-3.4.6源代码学习笔记(44)
- GCC-3.4.6源代码学习笔记(83)
- GCC-3.4.6源代码学习笔记(87)
- GCC-3.4.6源代码学习笔记(109)
- GCC-3.4.6源代码学习笔记(129 续)
- GCC-3.4.6源代码学习笔记(15)
- GCC-3.4.6源代码学习笔记(39)
- GCC-3.4.6源代码学习笔记(147-续1)
- GCC-3.4.6源代码学习笔记(75)
- GCC-3.4.6源代码学习笔记(120)
- GCC-3.4.6源代码学习笔记(153)
- GCC-3.4.6源代码学习笔记(81)
- GCC-3.4.6源代码学习笔记(136)
- GCC-3.4.6源代码学习笔记(84)
- GCC-3.4.6源代码学习笔记(162-续)
- GCC-3.4.6源代码学习笔记(89)
- GCC-3.4.6源代码学习笔记(139)
- GCC-3.4.6源代码学习笔记(28)
- GCC-3.4.6源代码学习笔记(12)