5.12.4.2.2.2.2. Parse argument list
Then cp_parser_enclosed_template_argument_list is invoked for parsing the enclosed template argument list within the template-id. Before the handling, greater_than_is_operator_p slot of parser should be set as false, as now coming “>” won’t be regarded as operator. And input “>>” within template argument list will be parsed as “>” and “>”, for example, “A<B<>> a”, front-end will take it as “A<B<> > a”. See the parser will try to recover from this error and go ahead, but not promise can generate correct code as user makes mistake here, so give out the error message.
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 }
Slot in_template_argument_list_p of parser if true indicates we are within template argument list. So first we need cache this slot of parser and set it as true temporarily before parsing the argument list.
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 }
Every argument in the list is parsed by cp_parser_template_argument . When all arguments handled, corresponding node generated are filled in TREE_VEC, and this vector is returned as returned value.
5.12.4.2.2.2.2.1. Parse argument
The syntax tree for template-argument is given in below.
According to [8], in a template-argument, an ambiguity between a type-id and an id-expression is resolved to a type-id, regardless of the form of the corresponding template-parameter (There is no such ambiguity in a default template-argument because the form of the template-parameter determines default template-argument must be type-id).
For example:
template <class T> void f();
template <int I> void f();
void g() {
f<int()>(); // int() is a type-id: call the first f()
}
So we try type-id at first.
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 }
Here a tricky case should be handled carefully. Considering the example given in above comments (this example can’t pass compiling, but not because of >>):
struct X { int operator >> (int); };
template <int V> struct Foo {};
Foo<X() >> 5> r;
“X()” is the instance of type-id, but “X() >> 5” instead is the instance of shift-expression (a variant of assignment-expression, in which case “X()” is a postfix-expression). As parser should be greedy as possible, it should parse the string as shift-expresion. However with mistake, programmer may write “> >” as “>>” mistakenly to enlarge type-id into shift-expression in view of parser. So it needs remember this possibility when successfully parsing a type-id followed by “>>”. Then tries to reparse the tokens as shift-expression. Details is given in case of assignment-expression.
5.12.4.2.2.2.2.1.1. Case of type-id
From its syntax tree, we can see that type-id contains type-specifier-seq and optional abstract- declarator. After parsing, these parts are contained within a tree node of TREE_LIST with type-specifier-seq in purpose slot and abstract-declarator in value field.
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 }
The syntax of type-specifier-seq is given below.
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 }
Funtion cp_parser_declarator is invoked recursively here but solely for abstract-declarator. As type-id is syntactically a declaration for an object or function of that type that omits the name of the object or function, it is the name of a type. Tree node of *_TYPE should be created according to the parsing result by groktypename .
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 }
Above, attributes and type-specifier are chained tegother into a same list. It needs split this list into two lists respectively. Below argument declspecs will hold the type-specifier-seq, and prefix_attributes will store attribute list if present. Condition at line 341 finds an integer constant, i.e. ‘5’ etc. And if spec_attrs is not tree_list, that means no attribute present.
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 }
For type-specifier-seq, at here, it can see that type-specifiers are always chained via value slot of tree_list , and abstract-declarator tegother with its attributes are always chained by purpose slot deliberately. Routine grokdeclarator then returns corresponding TYPE_DECL node for the type of the object or function. We have seen several examples of it in previous sections, so just skip it here. Next attributes of type-id will be installed into this TYPE_DECL node by cplus_decl_attributes .
In section 4.3.1.7.5.6.5. Processing attributes of builtin , we have seen that the front-end has used data structure attribute_spec to describe every attribute. There are tables common_attribute_table , attribute_table , format_attribute_table for C++, and format_attribute_table for x86 (the target machine), which predefine all attributes can be used with the language and upon specified target.
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 }
When invoking decl_attributes , we can specify the attributes to be installed by setting argument flags with certain value of enum attribute_flags , and unconsumed attributes will be returned in a list. Here we specify flags of 0 that means consuming all attributes provided.
In section 4.3.1.7.5.6.5. Processing attributes of builtin , we have seen that most attributes have an associated handler which will make appropriate modification upon the tree node. Besides, attributes appiled will be chained into attributes field of the tree node by *_ATTRIBUTES macros which also can be used as a fast way to find out what attributes in effect for the node.
5.12.4.2.2.2.2.1.2. Case of id-expression
If it is not type-id, we then reparse the tokens as 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;
An example of cp_parser_id_expression is given in section 5.12.3.2.1.1.3.4.1. Parse declarator . If the result of look-up is not of TYPE_DECL or CPP_TEMPLATE_ID, it must be an identifier if no error occurred; and the name should be further look up to find out the associated declaraction as line 8401 does.
5.12.4.2.2.2.2.1.3. Case of assignment-expression
If we parse type-id successfully and see following “>>”, or if above attempts fail, template-argument may be in form of assignment-expression. For the case, the template-argument must be non-type ones. According to [3] , the candidate for non-type template argument should be:
— an integral constant-expression of integral or enumeration type; or
— the name of a non-type template-parameter; or
— the address of an object or function with external linkage, including function templates and function template-ids but excluding non-static class members, expressed as & id-expression where the & is optional if the name refers to a function or array, or if the corresponding template-parameter is a reference; or
— a pointer to member
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 }
During this template parsing as assignment-expression, if we see the first token is an identifier, from figure: syntax tree for statement , we can see that it must be the head of primary-expression within the syntax tree of assignment-expression. If primary-expression can be parsed successfully as template-argument, we are done.
Otherwise, it checks if there is leading & before the primary-expression. The argument of such form corresponds to the last two variants of non-type parameter (remember that the argument must be a compiling time constant, for pointer-to-member, it must be like: “&A::f”). Again if the template-argument can be parsed as primary-expression, we are done this time too. We don’t step into the detail of handling primary-expression now. Some explainations can be found in section 5.12.4.1.2. Non-type parameter .
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 }
Above qualifying_class is set by cp_parser_primary_expression , it if non-null gives the class that is used as the qualifying class in the pointer-to-member. If qualifyng_class is set, at line 8461, finish_qualified_id_expr searches argument within the context of qualifying_class , and builds corresponding OFFSET_REF node for expression like: “A::f” or “a.*f”. Then build_x_unary_op at line 8489 builds the ADDR_EXPR for expression like: “&A::f”.
If above attemps fail, then have a look at syntax tree of assignment-expression, non-type template-argument must be constant expression as required by [3] . In the syntax tree, the second and third rules can’t be constant-expression; what’s more, constant-expression can simply degrade to condition-expression (xxx? xxx: xxx).
assignment-expression
├ condition-expression
| Ⅼ condition-expression
├ logical-or-expression assignment-operator assignment-expression
Ⅼ throw-expression
So next we try constant-expression (as degraded from assignment-expression above). See maybe_type_id below if true indicates at first parsing following the syntax of type-id is success and following “>>” is seen. So if maybe_type_id is set, it means we try to parse the template-argument as shift-expression which can be covered by constant-expression syntactically.
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 }
If maybe_type_id is unset, it is our last chance, returns the result anyway without checking the error (error message must be generated by handling function). Otherwise, we need check that the shift-experssion forms the argument correctly – that is whether it is followed by “,” or “>” (Note, if gives a correct non-type argument for type parameter mistakenly, this error can’t be recognized here, but in later processing, this type mismatching will be found). If not, reparse the tokens as type-id as it is very possible user types “> >” as “>>” and compiler can give out more reasonable error message (look back in cp_parser_enclosed_template_argument_list , it will handle the extra “>>” tokens found).