Studying note of GCC-3.4.6 source (123)

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.

(Click here for open )

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).

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值