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

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

}


<>
”之间的就是实参列表。对于函数模板,实参列表可以是空的,只要从函数的调用实参可以无二义性地推导出模板实参。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: