GCC-3.4.6源代码学习笔记(114)

5.12.4.      第二个例子

我们已经看过了解析器处理类模板“ SingleThreaded ”的过程,不过这个例子作为模板声明来说相当简单。接下来,我们来看一个从“ SingleThreaded ”派生来的模板声明,它能启示我们前端是如何处理模板模板参数及继承关系。下面是我们将要处理的 class-head

    template

    <

        template <class > class ThreadingModel = DEFAULT_THREADING,

        std ::size_t chunkSize = DEFAULT_CHUNK_SIZE,

        std ::size_t maxSmallObjectSize = MAX_SMALL_OBJECT_SIZE

    >

    class SmallObject : public ThreadingModel<

        SmallObject<ThreadingModel, chunkSize, maxSmallObjectSize> >

其中, DEFAULT_THREADING 是“ ::Loki::SingleThreaded ”的别名。该声明遵循以下规则:

template-declaration:

     export [opt] template-parameter-list-seq decl-specifier-seq [opt] init-declarator [opt] ;

5.12.4.1.              解析模板参数列表
5.12.4.1.1.        模板模板参数
5.12.4.1.1.1.  参数

如同前一个例子,经受如下调用栈 cp_parser_template_declaration à cp_parser_template_declaration_after_export à begin_template_parm_list (插入作用域 sk_template_parms ), cp_parser_template_parameter_list à cp_parser_template_parameter à cp_parser_type_parameter ,该声明运行以下 cp_parser_type_parameter 的代码。

 

7720   static tree

7721   cp_parser_type_parameter (cp_parser* parser)                                            in parser.c

7722   {

7723     cp_token *token;

7724     tree parameter;

7725  

7726     /* Look for a keyword to tell us what kind of parameter this is.  */

7727     token = cp_parser_require (parser, CPP_KEYWORD,

7728                           "`class', `typename', or `template'");

7729     if (!token)

7730       return error_mark_node;

7731  

7732     switch (token->keyword)

7733     {

7734       case RID_CLASS:

7735       case RID_TYPENAME:

7736       {

            ...

7764       }

7765       break ;

7766  

7767       case RID_TEMPLATE:

7768       {

7769         tree parameter_list;

7770         tree identifier;

7771         tree default_argument;

7772  

7773         /* Look for the `<'.  */

7774         cp_parser_require (parser, CPP_LESS, "`<'");

7775         /* Parse the template-parameter-list.  */

7776         begin_template_parm_list ();

7777         parameter_list

7778            = cp_parser_template_parameter_list (parser);

7779         parameter_list = end_template_parm_list (parameter_list);

 

我们例子的第一个模板参数是以关键字 template 开头的模板模板参数。这个关键字 template 使得事情变得有趣——一个额外的 sk_template_parms 作用域被加入,我们将得到如下的结构。

96

96 :处理模板模板参数之前

对于这个模板模板参数,它本身也是一个模板声明。这里在这个例子中,这个模板模板参数是:“ template <class> class ThreadingModel ”,现在开头的“ template < ”被解析器消化掉了。因此在 cp_parser_template_parameter (由 7778 行的 cp_parser_template_parameter_list 调用)中,以下代码将为下一个进入的符号“ class ”所执行。

 

7654   static tree

7655   cp_parser_template_parameter (cp_parser* parser)                                      in parser.c

7656   {

7657     cp_token *token;

7658  

7659     /* Peek at the next token.  */

7660     token = cp_lexer_peek_token (parser->lexer);

7661     /* If it is `class' or `template', we have a type-parameter.  */

7662     if (token->keyword == RID_TEMPLATE)

7663       return cp_parser_type_parameter (parser);

7664     /* If it is `class' or `typename' we do not know yet whether it is a

7665       type parameter or a non-type parameter. Consider:

7666  

7667       template <typename T, typename T::X X> ...

7668  

7669       or:

7670       

7671       template <class C, class D*> ...

7672  

7673       Here, the first parameter is a type parameter, and the second is

7674       a non-type parameter. We can tell by looking at the token after

7675       the identifier -- if it is a `,', `=', or `>' then we have a type

7676       parameter.  */

7677     if (token->keyword == RID_TYPENAME || token->keyword == RID_CLASS)

7678     {

7679        /* Peek at the token after `class' or `typename'.  */

7680       token = cp_lexer_peek_nth_token (parser->lexer, 2);

7681       /* If it's an identifier, skip it.  */

7682       if (token->type == CPP_NAME)

7683         token = cp_lexer_peek_nth_token (parser->lexer, 3);

7684       /* Now, see if the token looks like the end of a template

7685         parameter.  */

7686       if (token->type == CPP_COMMA

7687          || token->type == CPP_EQ

7688          || token->type == CPP_GREATER)

7689         return cp_parser_type_parameter (parser);

7690     }

         …

7703   }

 

显然,“ <class> ”部分是该模板模板参数声明中的模板参数;这听起来怪怪的,但正反映了 C++ 的功能强大。模板可以嵌套至深的层次——标准规定至少要允许 12 层,事实上,商业编译器都允许不少于 128 层的嵌套。

对于这个模板参数“ <class> ”, cp_parser_type_parameter 被递归调用。

 

7720   static tree

7721   cp_parser_type_parameter (cp_parser* parser)                                            in parser.c

7722   {

7723     cp_token *token;

7724     tree parameter;

7725  

7726     /* Look for a keyword to tell us what kind of parameter this is.  */

7727     token = cp_parser_require (parser, CPP_KEYWORD,

7728                            "`class', `typename', or `template'");

7729     if (!token)

7730       return error_mark_node;

7731  

7732     switch (token->keyword)

7733     {

7734       case RID_CLASS:

7735       case RID_TYPENAME:

7736       {

7737         tree identifier;

7738         tree default_argument;

7739  

7740         /* If the next token is an identifier, then it names the

7741           parameter.  */

7742         if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))

7743           identifier = cp_parser_identifier (parser);

7744         else

7745           identifier = NULL_TREE;

7746  

7747         /* Create the parameter.  */

7748         parameter = finish_template_type_parm (class_type_node, identifier);

7749  

7750         /* If the next token is an `=', we have a default argument.  */

7751         if (cp_lexer_next_token_is (parser->lexer, CPP_EQ))

7752          {

              ...

7757         }

7758         else

7759           default_argument = NULL_TREE;

7760  

7761          /* Create the combined representation of the parameter and the

7762           default argument.  */

7763         parameter = build_tree_list (default_argument, parameter);

7764       }

7765       break ;

          …

7848     }

7849    

7850     return parameter;

7851   }

 

上面的 finish_template_type_parm 为该参数构建了 tree_list 节点;并且在 7763 行将其整合入另一个 tree_list 节点。那么 parameter 指向如下的节点,因为该参数是匿名而且没有缺省参数。

97

97 :模板模板参数的节点

回到 cp_parser_template_parameter_list process_template_parm 打包模板的参数。注意到这是模板模板参数声明的模板参数!参数 next 指向上图中的 parameter 节点。

 

2161   tree

2162   process_template_parm (tree list, tree next)                                                       in pt.c

2163   {

2164     tree parm;

2165     tree decl = 0;

2166     tree defval;

2167     int is_type, idx;

2168  

2169     parm = next;

2170     my_friendly_assert (TREE_CODE (parm) == TREE_LIST, 259);

2171     defval = TREE_PURPOSE (parm);

2172     parm = TREE_VALUE (parm);

2173     is_type = TREE_PURPOSE (parm) == class_type_node;

2174  

2175     if (list)

2176     {

          …

2184     }

2185     else

2186       idx = 0;

2187  

2188     if (!is_type)

2189     {

          …

2212     }

2213     else

2214     {

2215       tree t;

2216       parm = TREE_VALUE (parm);

2217        

2218       if (parm && TREE_CODE (parm) == TEMPLATE_DECL)

2219       {

            ...

2226       }

2227       else

2228       {

2229         t = make_aggr_type (TEMPLATE_TYPE_PARM);

2230         /* parm is either IDENTIFIER_NODE or NULL_TREE.  */

2231         decl = build_decl (TYPE_DECL, parm, t);

2232       }

2233          

2234       TYPE_NAME (t) = decl;

2235       TYPE_STUB_DECL (t) = decl;

2236       parm = decl;

2237       TEMPLATE_TYPE_PARM_INDEX (t)

2238           = build_template_parm_index (idx, processing_template_decl ,

2239                                    processing_template_decl ,

2240                                    decl, TREE_TYPE (parm));

2241     }

2242     DECL_ARTIFICIAL (decl) = 1;

2243     SET_DECL_TEMPLATE_PARM_P (decl);

2244     pushdecl (decl);

2245     parm = build_tree_list (defval, parm);

2246     return chainon (list, parm);

2247   }

 

此处, begin_template_parm_list 目前已经被调用了 2 次,所以 processing_template_decl 2 。注意到 TEMPLATE_TPYE_PARM TYPE_DECL 是匿名的,因此在下面的 pushdecl 中,这个 TYPE_DECL ,通过 add_decl_to_level ,被链入相关 cxx_scope 对象的 names 域。

 

566    tree

567    pushdecl (tree x)                                                                                     in name-lookup.c

568    {

569      tree t;

570      tree name;

571      int need_new_binding;

572   

573      timevar_push (TV_NAME_LOOKUP);

574   

575      need_new_binding = 1;

576   

577      if (DECL_TEMPLATE_PARM_P (x))

578        /* Template parameters have no context; they are not X::T even

579          when declared within a class or namespace.  */

580        ;

581      else

582      {

          …

602      }

603   

604      name = DECL_NAME (x);

605      if (name)

606      {

          …

1007     }

1008  

1009     if (need_new_binding)

1010       add_decl_to_level (x,

1011                       DECL_NAMESPACE_SCOPE_P (x)

1012                       ? NAMESPACE_LEVEL (CP_DECL_CONTEXT (x))

1013                        : current_binding_level);

1014  

1015     POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, x);

1016   }

 

那么从 cp_parser_template_parameter_list 回到外面的 cp_parser_type_parameter end_template_parm_list 接下来准备 current_template_parms 。而返回的 parameter_list 就如下图。

点此打开

98 :模板模板参数声明中的模板参数列表

下一个符号必须是“ > class identifier [opt] ”。由这些符号,这个模板模板参数开始形成。

 

cp_parser_type_parameter (continue)

 

7780          /* Look for the `>'.  */

7781         cp_parser_require (parser, CPP_GREATER, "`>'");

7782         /* Look for the `class' keyword.  */

7783         cp_parser_require_keyword (parser, RID_CLASS, "`class'");

7784         /* If the next token is an `=', then there is a

7785           default-argument. If the next token is a `>', we are at

7786           the end of the parameter-list. If the next token is a `,',

7787           then we are at the end of this parameter.  */

7788         if (cp_lexer_next_token_is_not (parser->lexer, CPP_EQ)

7789            && cp_lexer_next_token_is_not (parser->lexer, CPP_GREATER)

7790            && cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA))

7791         {

7792           identifier = cp_parser_identifier (parser);

7793           /* Treat invalid names as if the parameter were nameless. */

7794           if (identifier == error_mark_node)

7795             identifier = NULL_TREE;

7796         }

7797         else

7798           identifier = NULL_TREE;

7799  

7800         /* Create the template parameter.  */

7801         parameter = finish_template_template_parm (class_type_node ,

7802                                              identifier);

 

这个模板模板参数是一个用于模板参数的模板声明,它应该有一个 TEMPLATE_DECL 来代表这个模板声明。

 

1943   tree

1944   finish_template_template_parm (tree aggr, tree identifier)                    in semantics.c

1945   {

1946     tree decl = build_decl (TYPE_DECL, identifier, NULL_TREE);

1947     tree tmpl = build_lang_decl (TEMPLATE_DECL, identifier, NULL_TREE);

1948     DECL_TEMPLATE_PARMS (tmpl) = current_template_parms ;

1949     DECL_TEMPLATE_RESULT (tmpl) = decl;

1950     DECL_ARTIFICIAL (decl) = 1;

1951     end_template_decl ();

1952  

1953     my_friendly_assert (DECL_TEMPLATE_PARMS (tmpl), 20010110);

1954  

1955     return finish_template_type_parm (aggr, tmpl);

1956   }

 

因为当可选的标识符被读入时,这个模板声明就结束了, end_template_decl 必须被调用来使 processing_template_decl 减一,并跳回该声明的绑定域(看到这是 sk_template_parms )。进一步, finish_template_type_parm 把这个 TEMPLATE_DECL 打包入模板参数的节点。因此在解析缺省参数前,我们得到如下图形。

点此打开

99 :构建的模板模板参数

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值