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

5.12.3.2.1.1.1.3.    为类创建TEMPLATE_DECL

因为这是个类模板,它必须要有自己的TEMPLATE_DECL节点来描述其模板特性。现在就要创建这个节点。

 

pushtag (continue)

 

4656       d = maybe_process_template_type_declaration (type,

4657                                              globalize, b);

 

当前,processing_template_decl为非0值,因为我们正在处理类模板。不过因为模板参数已经被处理,processing_template_parmlist0。注意,参数type指向类的RECORD_TYPE节点。

 

4525 static tree

4526 maybe_process_template_type_declaration (tree type, int globalize,        in name-lookup.c

4527                                     cxx_scope *b)

4528 {

4529   tree decl = TYPE_NAME (type);

4530

4531   if (processing_template_parmlist)

4532     /* You can't declare a new template type in a template parameter

4533       list. But, you can declare a non-template type:

4534

4535         template <class A*> struct S;

4536

4537       is a forward-declaration of `A'.  */

4538     ;

4539   else

4540   {

4541     my_friendly_assert (IS_AGGR_TYPE (type)

4542                     || TREE_CODE (type) == ENUMERAL_TYPE, 0);

4543

4544     if (processing_template_decl)

4545     {

4546       /* This may change after the call to

4547         push_template_decl_real, but we want the original value.  */

4548       tree name = DECL_NAME (decl);

4549

4550       decl = push_template_decl_real (decl, globalize);

4551       /* If the current binding level is the binding level for the

4552         template parameters (see the comment in

4553         begin_template_parm_list) and the enclosing level is a class

4554         scope, and we're not looking at a friend, push the

4555         declaration of the member class into the class scope.  In the

4556         friend case, push_template_decl will already have put the

4557         friend into global scope, if appropriate.  */

4558       if (TREE_CODE (type) != ENUMERAL_TYPE

4559         && !globalize && b->kind == sk_template_parms

4560         && b->level_chain->kind == sk_class)

4561       {

            

4577       }

4578     }

4579   }

4580

4581   return decl;

4582 }

 

除了我们在中间树里已经看到的节点,模板声明需要额外的节点。模板引入了具现(instantion),特化(specializaiton),偏特化(partial specialization)这些概念,需要的新的节点来记录这些概念间的关系。

 

2770 tree

2771 push_template_decl_real (tree decl, int is_friend)                                                in pt.c

2772 {

2773   tree tmpl;

2774   tree args;

2775   tree info;

2776   tree ctx;

2777   int primary;

2778   int is_partial;

2779   int new_template_p = 0;

2780

2781   /* See if this is a partial specialization.  */

2782   is_partial = (DECL_IMPLICIT_TYPEDEF_P (decl)

2783        && TREE_CODE (TREE_TYPE (decl)) != ENUMERAL_TYPE

2784        && CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (decl)));

2785

2786   is_friend |= (TREE_CODE (decl) == FUNCTION_DECL && DECL_FRIEND_P (decl));

2787

2788   if (is_friend)

2789     /* For a friend, we want the context of the friend function, not

2790       the type of which it is a friend.  */

2791     ctx = DECL_CONTEXT (decl);

2792   else if (CP_DECL_CONTEXT (decl)

2793         && TREE_CODE (CP_DECL_CONTEXT (decl)) != NAMESPACE_DECL)

2794     /* In the case of a virtual function, we want the class in which

2795       it is defined.  */

2796     ctx = CP_DECL_CONTEXT (decl);

2797   else

2798     /* Otherwise, if we're currently defining some class, the DECL

2799       is assumed to be a member of the class.  */

2800     ctx = current_scope ();

2801

2802   if (ctx && TREE_CODE (ctx) == NAMESPACE_DECL)

2803     ctx = NULL_TREE;

2804

2805   if (!DECL_CONTEXT (decl))

2806     DECL_CONTEXT (decl) = FROB_CONTEXT (current_namespace);

2807

2808   /* See if this is a primary template.  */

2809   primary = template_parm_scope_p ();

 

如同其他的声明,在处理之前,需要确定其所在的作用域。这里CP_DECL_CONTEXT实际上调用DECL_CONTEXT。对于这个例子,DECL_CONTEXT是名字空间“Loki”,它之前在pushtag4652行设置好了。那么ctx2800行被设置为NULL

 

1512 bool

1513 template_parm_scope_p (void)                                                            in name-lookup.c

1514 {

1515   return innermost_scope_kind () == sk_template_parms;

1516 }

 

注意到现在current_binding_level指向sk_template_parms

 

1504 scope_kind

1505 innermost_scope_kind (void)                                                                      in name-lookup.c

1506 {

1507   return current_binding_level->kind;

1508 }

 

非偏特化及特化的模板声明称为主声明(primary declaration)。上面的例程template_parm_scope_p通过检查最接近的封装作用域(the closest enclosing scope)来区分这些声明。对于我们的例子,这个作用域是sk_template_parmsprimary将是非0值。

 

push_template_decl_real (continue)

 

2811   if (primary)

2812   {

2813     if (current_lang_name == lang_name_c)

2814       error ("template with C linkage");

2815     else if (TREE_CODE (decl) == TYPE_DECL

2816           && ANON_AGGRNAME_P (DECL_NAME (decl)))

2817       error ("template class without a name");

2818     else if (TREE_CODE (decl) == FUNCTION_DECL)

2819     {

          

2843     }

2844     else if (DECL_IMPLICIT_TYPEDEF_P (decl)

2845           && CLASS_TYPE_P (TREE_TYPE (decl)))

2846       /* OK */;

2847     else

2848     {

2849       error ("template declaration of `%#D'", decl);

2850       return error_mark_node;

2851     }

2852   }

2853

2854   /* Check to see that the rules regarding the use of default

2855     arguments are not being violated.  */

2856   check_default_tmpl_args (decl, current_template_parms,

2857                        primary, is_partial);

2858

2859   if (is_partial)

2860     return process_partial_specialization (decl);

2861

2862   args = current_template_args ();

 

上面,check_default_tmpl_args不作任何事,因为我们仍然在模板的声明里(实际是定义)。正如在解析模板类型参数一节所看到的,current_template_parms为该模板声明保存了适用的模板参数。而对于嵌套的模板声明,最里层的参数出现在由该变量指向的链表的开头。

 

2297 tree

2298 current_template_args (void)                                                                             in pt.c

2299 {

2300   tree header;

2301   tree args = NULL_TREE;

2302   int length = TMPL_PARMS_DEPTH (current_template_parms);

2303   int l = length;

2304

2305   /* If there is only one level of template parameters, we do not

2306     create a TREE_VEC of TREE_VECs. Instead, we return a single

2307     TREE_VEC containing the arguments.  */

2308   if (length > 1)

2309     args = make_tree_vec (length);

2310

2311   for (header = current_template_parms; header; header = TREE_CHAIN (header))

2312   {

2313     tree a = copy_node (TREE_VALUE (header));

2314     int i;

2315

2316     TREE_TYPE (a) = NULL_TREE;

2317     for (i = TREE_VEC_LENGTH (a) - 1; i >= 0; --i)

2318     {

2319       tree t = TREE_VEC_ELT (a, i);

2320

2321       /* T will be a list if we are called from within a

2322         begin/end_template_parm_list pair, but a vector directly

2323         if within a begin/end_member_template_processing pair.  */

2324       if (TREE_CODE (t) == TREE_LIST)

2325       {

2326         t = TREE_VALUE (t);

2327        

2328         if (TREE_CODE (t) == TYPE_DECL

2329            || TREE_CODE (t) == TEMPLATE_DECL)

2330           t = TREE_TYPE (t);

2331         else

2332          t = DECL_INITIAL (t);

2333         TREE_VEC_ELT (a, i) = t;

2334       }

2335     }

2336

2337     if (length > 1)

2338       TREE_VEC_ELT (args, --l) = a;

2339     else

2340       args = a;

2341   }

2342

2343   return args;

2344 }

 

以图嵌套模板参数的布局为例,在2302行的TMPL_PARMS_DEPTH返回保存在purpose域的值,而current_template_args将返回如下图的args。看到参数被封装成更紧凑的形式,并且调转节点的次序,以最外层的参数在开头。变量current_template_parms保证了其正确性。

53:由current_template_args返回的参数

继续这个函数,这里的ctx,正如我们在上面看到的,是NULL(它在上面的2800行被设置为NULL),因此2864行的条件被满足。

 

push_template_decl_real (continue)

 

2864   if (!ctx

2865       || TREE_CODE (ctx) == FUNCTION_DECL

2866       || (CLASS_TYPE_P (ctx) && TYPE_BEING_DEFINED (ctx))

2867       || (is_friend && !DECL_TEMPLATE_INFO (decl)))

2868   {

2869     if (DECL_LANG_SPECIFIC (decl)

2870        && DECL_TEMPLATE_INFO (decl)

2871        && DECL_TI_TEMPLATE (decl))

2872       tmpl = DECL_TI_TEMPLATE (decl);

2873     /* If DECL is a TYPE_DECL for a class-template, then there won't

2874       be DECL_LANG_SPECIFIC. The information equivalent to

2875       DECL_TEMPLATE_INFO is found in TYPE_TEMPLATE_INFO instead.  */

2876     else if (DECL_IMPLICIT_TYPEDEF_P (decl)

2877           && TYPE_TEMPLATE_INFO (TREE_TYPE (decl))

2878           && TYPE_TI_TEMPLATE (TREE_TYPE (decl)))

2879     {

          

2888     }

2889     else

2890     {

2891       tmpl = build_template_decl (decl, current_template_parms);

2892       new_template_p = 1;

2893

2894       if (DECL_LANG_SPECIFIC (decl)

2895          && DECL_TEMPLATE_SPECIALIZATION (decl))

2896       {

2897         /* A specialization of a member template of a template

2898           class.  */

2899         SET_DECL_TEMPLATE_SPECIALIZATION (tmpl);

2900         DECL_TEMPLATE_INFO (tmpl) = DECL_TEMPLATE_INFO (decl);

2901         DECL_TEMPLATE_INFO (decl) = NULL_TREE;

2902       }

2903     }

2904   }

 

作为正在被定义的模板,其RECORD_TYPE节点的域TYPE_TEMPLATE_INFOTYPE_TI_TEMPLATE都是NULL。现在要为模板声明创建树节点了。

 

2349 static tree

2350 build_template_decl (tree decl, tree parms)                                                                in pt.c

2351 {

2352   tree tmpl = build_lang_decl (TEMPLATE_DECL, DECL_NAME (decl), NULL_TREE);

2353   DECL_TEMPLATE_PARMS (tmpl) = parms;

2354   DECL_CONTEXT (tmpl) = DECL_CONTEXT (decl);

2355   if (DECL_LANG_SPECIFIC (decl))

2356   {

2357     DECL_STATIC_FUNCTION_P (tmpl) = DECL_STATIC_FUNCTION_P (decl);

2358     DECL_CONSTRUCTOR_P (tmpl) = DECL_CONSTRUCTOR_P (decl);

2359     DECL_DESTRUCTOR_P (tmpl) = DECL_DESTRUCTOR_P (decl);

2360     DECL_NONCONVERTING_P (tmpl) = DECL_NONCONVERTING_P (decl);

2361     DECL_ASSIGNMENT_OPERATOR_P (tmpl) = DECL_ASSIGNMENT_OPERATOR_P (decl);

2362     if (DECL_OVERLOADED_OPERATOR_P (decl))

2363       SET_OVERLOADED_OPERATOR_CODE (tmpl,

2364                                   DECL_OVERLOADED_OPERATOR_P (decl));

2365   }

2366

2367   return tmpl;

2368 }

 

这里参数declbuild_decl创建,其域lang_specificNULL。因此被2355IF块所包含的代码被跳过。而在push_template_decl_real2894行的IF块亦被跳过。

在前端中,定义了许多访问模板相关节点中的域的宏。这些宏在GCC源代码中到处都在1。为了方便阅读,下图显示了指定宏访问的域及其访问的路径。

 

54:访问模板定义的宏

看到对于TYPE_DECL(注意,并非此处的decl,这个节点必须由build_lang_decl来创建)及RECORD_TYPE,都有名为lang_specific的域。虽然它们都指向不同类型的对象,这些对象都有域template_info。这些对象的差别在于,对于RECORD_TYPE,其template_info指向主模板(primary template)的对象,而对于TYPE_DECL,其template_info则指向模板的特化及偏特化的对象。显然,这些template_info不是指向同一个对象的。

 

push_template_decl_real (continue)

 

2997   DECL_TEMPLATE_RESULT (tmpl) = decl;

2998   TREE_TYPE (tmpl) = TREE_TYPE (decl);

2999

3000   /* Push template declarations for global functions and types. Note

3001     that we do not try to push a global template friend declared in a

3002     template class; such a thing may well depend on the template

3003     parameters of the class.  */

3004   if (new_template_p && !ctx

3005      && !(is_friend && template_class_depth (current_class_type) > 0))

3006     tmpl = pushdecl_namespace_level (tmpl);

 

这里new_template_ptrue,而对于当前类模板定义,template_class_depth返回0(因为DECL_TEMPLATE_INFO返回NULL),因此将把这个TEMPLATE_DECL加入名字空间“Loki”。

 

3229 tree

3230 pushdecl_namespace_level (tree x)                                                       in name-lookup.c

3231 {

3232   struct cp_binding_level *b = current_binding_level;

3233   tree t;

3234

3235   timevar_push (TV_NAME_LOOKUP);

3236   t = pushdecl_with_scope (x, NAMESPACE_LEVEL (current_namespace));

3237

3238   /* Now, the type_shadowed stack may screw us. Munge it so it does

3239     what we want.  */

3240   if (TREE_CODE (x) == TYPE_DECL)

3241   {

        

3268   }

3269   POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, t);

3270 }

 

这里current_binding_level返回绑定域sk_template_parms,不过当前情形下它没有用处。我们想要加入TEMPALTE_DECL的是名字空间“Loki”,它由current_namespace获得。

 

1941 tree

1942 pushdecl_with_scope (tree x, cxx_scope *level)                                     in name-lookup.c

1943 {

1944   struct cp_binding_level *b;

1945   tree function_decl = current_function_decl;

1946

1947   timevar_push (TV_NAME_LOOKUP);

1948   current_function_decl = NULL_TREE;

1949   if (level->kind == sk_class)

1950   {

1951     b = class_binding_level;

1952     class_binding_level = level;

1953     pushdecl_class_level (x);

1954     class_binding_level = b;

1955   }

1956   else

1957   {

1958     b = current_binding_level;

1959     current_binding_level = level;

1960     x = pushdecl (x);

1961     current_binding_level = b;

1962   }

1963   current_function_decl = function_decl;

1964   POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, x);

1965 }

 

注意到,在上面,首先current_binding_level被缓存,然后设置为名字空间“Loki”,因而现在pushdecl可以如我们期望那样去执行。下面的DECL_NAMESPACE_SCOPE_P检查x的上下文的类型是否为名字空间,而且现在current_binding_level暂时返回名字空间“Loki”的作用域,而不是作用域sk_template_parms。因此满足617行的条件。

 

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;

       

604      name = DECL_NAME (x);

605      if (name)

606      {

607        int different_binding_level = 0;

          

617        if (DECL_NAMESPACE_SCOPE_P (x) && namespace_binding_p ())

618          t = namespace_binding (name, DECL_CONTEXT (x));

619        else

620          t = lookup_name_current_level (name);

 

显然在名字空间“Loki”中尚没有名字“SingleThreaded”,因此在618行,t指向NULL

 

pushdecl (continue)

 

828        /* This name is new in its binding level.

829          Install the new declaration and return it.  */

830        if (namespace_bindings_p ())

831        {

832          /* Install a global value.  */

833   

834          /* If the first global decl has external linkage,

835            warn if we later see static one.  */

836          if (IDENTIFIER_GLOBAL_VALUE (name) == NULL_TREE && TREE_PUBLIC (x))

837            TREE_PUBLIC (name) = 1;

838   

839          /* Bind the name for the entity.  */

840          if (!(TREE_CODE (x) == TYPE_DECL && DECL_ARTIFICIAL (x)

841                 && t != NULL_TREE)

842              && (TREE_CODE (x) == TYPE_DECL

843                   || TREE_CODE (x) == VAR_DECL

844                   || TREE_CODE (x) == ALIAS_DECL

845                   || TREE_CODE (x) == NAMESPACE_DECL

846                   || TREE_CODE (x) == CONST_DECL

847                   || TREE_CODE (x) == TEMPLATE_DECL))

848            SET_IDENTIFIER_NAMESPACE_VALUE (name, x);

              

872        }

         

1003     }

1004  

1005     if (TREE_CODE (x) == VAR_DECL)

1006       maybe_register_incomplete_var (x);

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   }

 

SET_IDENTIFIER_NAMESPACE_VALUE仅是在其中调用set_namespace_binding。参数scopecurrent_namespace,而val是要加入的TEMPLATE_DECL

 

2958   void

2959   set_namespace_binding (tree name, tree scope, tree val)                       in name-lookup.c

2960   {

2961     cxx_binding *b;

2962  

2963     timevar_push (TV_NAME_LOOKUP);

2964     if (scope == NULL_TREE)

2965       scope = global_namespace;

2966     b = binding_for_name (NAMESPACE_LEVEL (scope), name);

2967     if (!b->value || TREE_CODE (val) == OVERLOAD || val == error_mark_node)

2968       b->value = val;

2969     else

2970       supplement_binding (b, val);

2971     timevar_pop (TV_NAME_LOOKUP);

2972   }

 

在名字空间中加入这个TEMPLATE_DECL后,中间树现在看起来如下图:

 

打开

55:加入类SingleThreaded的标签第二步

下面,DECL_CONV_FN_P如果非0,表示一个转换操作符;而对于这个TEMPLATE_DECL节点,其域DECL_TEMPLATE_INFONULL。又,因为当前的模板声明是主声明,3010行的DECL_PRIMRAY_TEMPLATE把最里层参数的type设为该模板声明(TEMPALTE_DECL),以显示这是个主模板。

 

push_template_decl_real (continue)

 

3008   if (primary)

3009   {

3010     DECL_PRIMARY_TEMPLATE (tmpl) = tmpl;

3011     if (DECL_CONV_FN_P (tmpl))

3012     {

3013       int depth = TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl));

3014

3015       /* It is a conversion operator. See if the type converted to

3016         depends on innermost template operands.  */

3017    

3018       if (uses_template_parms_level (TREE_TYPE (TREE_TYPE (tmpl)),

3019                                 depth))

3020         DECL_TEMPLATE_CONV_FN_P (tmpl) = 1;

3021     }

3022   }

3023

3024   /* The DECL_TI_ARGS of DECL contains full set of arguments refering

3025     back to its most general template. If TMPL is a specialization,

3026     ARGS may only have the innermost set of arguments. Add the missing

3027     argument levels if necessary.  */

3028   if (DECL_TEMPLATE_INFO (tmpl))

3029     args = add_outermost_template_args (DECL_TI_ARGS (tmpl), args);

3030

3031   info = tree_cons (tmpl, args, NULL_TREE);

3032

3033   if (DECL_IMPLICIT_TYPEDEF_P (decl))

3034   {

3035     SET_TYPE_TEMPLATE_INFO (TREE_TYPE (tmpl), info);

3036     if ((!ctx || TREE_CODE (ctx) != FUNCTION_DECL)

3037        && TREE_CODE (TREE_TYPE (decl)) != ENUMERAL_TYPE

3038        /* Don't change the name if we've already set it up.  */

3039        && !IDENTIFIER_TEMPLATE (DECL_NAME (decl)))

3040       DECL_NAME (decl) = classtype_mangled_name (TREE_TYPE (decl));

3041   }

3042   else if (DECL_LANG_SPECIFIC (decl))

3043     DECL_TEMPLATE_INFO (decl) = info;

3044

3045   return DECL_TEMPLATE_RESULT (tmpl);

3046 }

 

注意到在上面的代码中,DECL_IMPLICIT_TYPEDEF_P返回true,因为decl是由pushtag创建的隐式typedef声明。另外,DECL_TEMPLATE_INFO起初是NULL。但随后它被为SET_TYPE_TEMPLATE_INFO3034行所更新。在处理模板特化时,这个安排是有好处的,因为DECL_TEMPLATE_INFO指向了参数的拷贝(该拷贝被更新为特化的实际参数)。

 

56:加入类SingleThreaded的标签第三步

接下来,前端为这个模板类生成修饰名(mangled name)。

 

4002 static tree

4003 classtype_mangled_name (tree t)                                                                        in pt.c

4004 {

4005   if (CLASSTYPE_TEMPLATE_INFO (t)

4006      /* Specializations have already had their names set up in

4007        lookup_template_class.  */

4008     && !CLASSTYPE_TEMPLATE_SPECIALIZATION (t))

4009   {

4010     tree tmpl = most_general_template (CLASSTYPE_TI_TEMPLATE (t));

4011

4012     /* For non-primary templates, the template parameters are

4013       implicit from their surrounding context.  */

4014     if (PRIMARY_TEMPLATE_P (tmpl))

4015     {

4016       tree name = DECL_NAME (tmpl);

4017       char *mangled_name = mangle_class_name_for_template

4018                             (IDENTIFIER_POINTER (name),

4019                              DECL_INNERMOST_TEMPLATE_PARMS (tmpl),

4020                              CLASSTYPE_TI_ARGS (t));

4021       tree id = get_identifier (mangled_name);

4022       IDENTIFIER_TEMPLATE (id) = name;

4023       return id;

4024     }

4025   }

4026

4027   return TYPE_IDENTIFIER (t);

4028 }

 

例程most_general_template,如其名所表示,返回最普适的模板(即主模板)。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值