您的位置:首页 > 编程语言

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

,它还将处理额外的“
>>
”返回)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: