Studying note of GCC-3.4.6 source (89)

5.12.3.      The second statement – TEMPLATE_DECL

The second statement is template-declaration, and the abbreviate syntax tree is shown in below. The first syntax is the declaration of class template, and the second one is the declaration of function template. Now we are defining the template class.

template-declaration

export [opt] template < template-parameter-list> decl-specific-seq [opt] init-declarator [opt];

export [opt] template < template- parameter -list> function-definition

In cp_parser_declaration , following code segement handles template related definition.

 

cp_parser_declaration (continue)

 

6306    /* If the next token is `template', then we have either a template

6307      declaration, an explicit instantiation, or an explicit

6308      specialization.  */

6309    else if (token1.keyword == RID_TEMPLATE)

6310     {

6311       /* `template <>' indicates a template specialization.  */

6312      if (token2.type == CPP_LESS

6313          && cp_lexer_peek_nth_token (parser->lexer, 3)->type == CPP_GREATER)

6314        cp_parser_explicit_specialization (parser);

6315      /* `template <' indicates a template declaration.  */

6316      else if (token2.type == CPP_LESS)

6317        cp_parser_template_declaration (parser, /*member_p=*/ false);

6318       /* Anything else must be an explicit instantiation.  */

6319      else

6320        cp_parser_explicit_instantiation (parser);

6321    }

6322     /* If the next token is `export', then we have a template

6323      declaration.  */

6324    else if (token1.keyword == RID_EXPORT)

6325      cp_parser_template_declaration (parser, /*member_p=*/ false);

6326     /* If the next token is `extern', 'static' or 'inline' and the one

6327      after that is `template', we have a GNU extended explicit

6328      instantiation directive.  */

6329    else if (cp_parser_allow_gnu_extensions_p (parser)

6330          && (token1.keyword == RID_EXTERN

6331               || token1.keyword == RID_STATIC

6332               || token1.keyword == RID_INLINE)

6333           && token2.keyword == RID_TEMPLATE)

6334      cp_parser_explicit_instantiation (parser);

 

When seeing the heading tokens: “template <class Host> class SingleThreaded”, parser can know it’s a template declaration at line 6316, and invokes the handler.

 

7593 static void

7594 cp_parser_template_declaration (cp_parser* parser, bool member_p)              in parser.c

7595 {

7596    /* Check for `export'.  */

7597    if (cp_lexer_next_token_is_keyword (parser->lexer, RID_EXPORT))

7598    {

7599       /* Consume the `export' token.  */

7600      cp_lexer_consume_token (parser->lexer);

7601      /* Warn that we do not support `export'.  */

7602      warning ("keyword `export' not implemented, and will be ignored");

7603    }

7604

7605    cp_parser_template_declaration_after_export (parser, member_p);

7606 }

 

Keyword export is used in separation compilation model. With the separation compilation model, the class template definition and the definitions of its inline member functions are placed in a header file, whereas the definitions of the non-inline member functions and static data members are placed in a program text file. With this model, the definitions for a class template and its members are organized in the same way we organize the definitions of nontemplate classes and their members. But this version can’t support it.

 

14420 static void

14421 cp_parser_template_declaration_after_export (cp_parser* parser, bool member_p) in parser.c

14422 {

14423    tree decl = NULL_TREE;

14424    tree parameter_list;

14425    bool friend_p = false;

14426

14427    /* Look for the `template' keyword.  */

14428    if (!cp_parser_require_keyword (parser, RID_TEMPLATE, "`template'"))

14429      return ;

14430       

14431    /* And the `<'.  */

14432    if (!cp_parser_require (parser, CPP_LESS, "`<'"))

14433      return ;

14434       

14435    /* If the next token is `>', then we have an invalid

14436      specialization. Rather than complain about an invalid template

14437      parameter, issue an error message here.  */

14438    if (cp_lexer_next_token_is (parser->lexer, CPP_GREATER))

14439    {

14440      cp_parser_error (parser, "invalid explicit specialization");

14441      begin_specialization ();

14442      parameter_list = NULL_TREE;

14443    }

14444    else

14445    {

14446       /* Parse the template parameters.  */

14447      begin_template_parm_list ();

14448      parameter_list = cp_parser_template_parameter_list (parser);

14449      parameter_list = end_template_parm_list (parameter_list);

14450    }

 

As we know that declaration like class T in template parameter list is not a normal class declaration, but somewhat a place-holder, then during template instantiation it will be replaced by specified type appropriately. It is important to separate this type declaration from current binding scope and place it into special ones (i.e, sk_template_parms ).

 

598  void

599  begin_template_parm_list (void)                                                                         in pt.c

600  {

601    /* We use a non-tag-transparent scope here, which causes pushtag to

602      put tags in this scope, rather than in the enclosing class or

603      namespace scope. This is the right thing, since we want

604      TEMPLATE_DECLS, and not TYPE_DECLS for template classes. For a

605      global template class, push_template_decl handles putting the

606      TEMPLATE_DECL into top-level scope. For a nested template class,

607      e.g.:

608 

609         template <class T> struct S1 {

610           template <class T> struct S2 {};

611         };

612 

613      pushtag contains special code to call pushdecl_with_scope on the

614      TEMPLATE_DECL for S2.  */

615    begin_scope (sk_template_parms, NULL);

616    ++processing_template_decl ;

617    ++processing_template_parmlist ;

618    note_template_header (0);

619  }

 

Above processing_template_decl refers to x_processing_template_decl field of scope_chain . It and global variable processing_template_parmlist records the depth of template declaration the template parameter list being processed.

 

687  static void

688  note_template_header (int specialization)                                                            in pt.c

689  {

690    processing_specialization = specialization;

691    template_header_count ++;

692  }

 

The layout after pushing the special sk_template_parms scope is shown as below.


 

Figure 47 : brief layout after pushing sk_template_parm

5.12.3.1.              Parse template parameter list

Here processing_specialization refers the slot x_processing_specialization of scope_chain , it is nonzero if template specification is found (i.e, seeing template <> ). And global variable template_header_count if nonzero indicates seeing template header (i.e, template ).

From the abbreviate syntax tree below, surprising to see the complexity it may be.

template < template-parameter-list >

template-parameter

template-parameter-list , template-parameter

type-parameter

|  class identifier [opt]

|  class identifier [opt] = type-id

|  typename identifier [opt]

|  template < template-parameter-list > class identifer [opt]

|  template < template-parameter-list > class identifer [opt] = id-expression

|

parameter-declaration

decl-specifier-seq declarator

decl-specifier-seq declarator = assignment-expression

decl-specifier-seq abstract-declarator [opt]

decl-specifier-seq abstract-declarator [opt] = assignment-expression

As the parameter list can contain any number of parameter, token of comma drives the WHILE loop in below at line 7622.

 

7617 static tree

7618 cp_parser_template_parameter_list (cp_parser* parser)                                  in parser.c

7619 {

7620   tree parameter_list = NULL_TREE;

7621

7622   while (true)

7623   {

7624     tree parameter;

7625     cp_token *token;

7626

7627     /* Parse the template-parameter.  */

7628     parameter = cp_parser_template_parameter (parser);

7629     /* Add it to the list.  */

7630     parameter_list = process_template_parm (parameter_list,

7631                                       parameter);

7632

7633      /* Peek at the next token.  */

7634     token = cp_lexer_peek_token (parser->lexer);

7635     /* If it's not a `,', we're done.  */

7636     if (token->type != CPP_COMMA)

7637       break ;

7638     /* Otherwise, consume the `,' token.  */

7639     cp_lexer_consume_token (parser->lexer);

7640   }

7641

7642   return parameter_list;

7643 }

 

In the above syntax tree, type-parameter of template-parameter constructs type parameter, while parameter-declaration of template-parameter constructs non-type parameter. They contain very different nonterminals, however they still possible have common header for instance:

template < typename T, typename T::X X>, first T is type parameter, and second T::X is the non-type parameter.

Also, template <class C, class D*>, C is type parameter, and D* is the non-type one.

The related function needs handle these two variant carefully.

 

你可能感兴趣的:(list,tree,Class,processing,token,Instantiation)