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

5.12.5.2.2.2.1.1.2.            替换剩下的缺省实参

第二个参数是下图中由红色箭头指向的节点。因为第三个参数是类似的,在下面我们跳过它。

点此打开

那么在 coerce_template_parms 3835 行,当调用 tsubst_template_arg 时,被上面第二个参数的 purpose 域所引用的 tree_list 节点,被作为第一个实参传入。在 tsubst_template_arg 中,接着调用 tsubst_expr ,该函数为非语句( non-statement )调用 tsubst_copy_and_build 。然后在 tsubst_copy_and_build 中,调用 tsubst_copy ,并返回保存在 purpose 域的 INTEGER_CST 节点。而该节点被一直返回到 tsubst_template_arg

接着 convert_template_argument 被调用来产生合适的实参。在这里 parm 是由 value 域所指向的节点,而 arg 是被上图中红色箭头所指向的 tree_list 节点的 purpose 域。

 

3636   static tree

3637   convert_template_argument (tree parm,                                                            in pt.c

3638                           tree arg,

3639                           tree args,

3640                           tsubst_flags_t complain,

3641                           int i,

3642                           tree in_decl)

3643   {

3644     tree val;

3645     tree inner_args;

3646     int is_type, requires_type, is_tmpl_type, requires_tmpl_type;

3647    

3648     inner_args = INNERMOST_TEMPLATE_ARGS (args);

  …

3722     if (is_type)

3723     {

          …

3762     }

3763     else

3764     {

3765       tree t = tsubst (TREE_TYPE (parm), args, complain, in_decl);

3766  

3767       if (invalid_nontype_parm_type_p (t, complain))

3768         return error_mark_node;

3769        

3770       if (!uses_template_parms (arg) && !uses_template_parms (t))

3771         /* We used to call digest_init here. However, digest_init

3772           will report errors, which we don't want when complain

3773           is zero. More importantly, digest_init will try too

3774           hard to convert things: for example, `0' should not be

3775           converted to pointer type at this point according to

3776           the standard. Accepting this is not merely an

3777           extension, since deciding whether or not these

3778           conversions can occur is part of determining which

3779           function template to call, or whether a given explicit

3780           argument specification is valid.  */

3781         val = convert_nontype_argument (t, arg);

3782       else

3783         val = arg;

3784  

3785       if (val == NULL_TREE)

3786         val = error_mark_node;

3787       else if (val == error_mark_node && (complain & tf_error))

3788         error ("could not convert template argument `%E' to `%T'",

3789               arg, t);

3790     }

3791  

3792     return val;

3793   }

 

parm 的类型( TREE_TYPE )是 INTEGER_TYPE ,它由 tsubst 返回不作任何处理,并且因为 arg 指向 INTEGER_CST 节点,在 3781 行的 convert_nontype_argument 不能对 arg 做更多的简化。 So as last we just get the node pointed by arg as the final argument.

5.12.5.2.2.2.1.1.3.            生成节点

下面的 template_type 指向“ SmallObject ”的 RECORD_TYPE 节点,而 arglist 是下面的 tree_vec (忽略了第三个实参)。

点此打开

 

lookup_template_class (continue)

 

4356       /* In the scope of a template class, explicit references to the

4357         template class refer to the type of the template, not any

4358         instantiation of it. For example, in:

4359       

4360         template <class T> class C { void f(C<T>); }

4361  

4362         the `C<T>' is just the same as `C'. Outside of the

4363         class, however, such a reference is an instantiation.  */

4364       if (comp_template_args (TYPE_TI_ARGS (template_type),

4365                           arglist))

4366       {

4367         found = template_type;

4368         

4369         if (!entering_scope && PRIMARY_TEMPLATE_P (template))

4370         {

4371           tree ctx;

4372             

4373           for (ctx = current_class_type ;

4374               ctx && TREE_CODE (ctx) != NAMESPACE_DECL;

4375               ctx = (TYPE_P (ctx)

4376                     ? TYPE_CONTEXT (ctx)

4377                     : DECL_CONTEXT (ctx)))

4378             if (TYPE_P (ctx) && same_type_p (ctx, template_type))

4379               goto found_ctx;

4380             

4381           /* We're not in the scope of the class, so the

4382             TEMPLATE_TYPE is not the type we want after all.  */

4383           found = NULL_TREE;

4384       found_ctx:;

4385         }

4386       }

4387       if (found)

4388         POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, found);

 

上面的注释清楚地解释了上面代码的目的。对于注释中给出的例子,方法 f 一样被构建入 TEMPLATE_DECL ,但是因为它是模板类的方法,其参数列表由 current_template_args 生成。而 f 的参数“ C<T> ”是一个 template-id 。毫无疑问,其实参列表“ T ”与其封闭模板类的参数列表相同。

首先 comp_template_args 确保这两个列表是相同的。接着在 4369 行的 entering_scope 仅当我们将要进入所要查找类的作用域时,为非 0 值(那么处理 f 时,其为 0 )。因此在 4373 行的 FOR 块验证 template_type 是否为封闭类。如果是,它就是我们所期待的类型。

 

3899   int

3900   comp_template_args (tree oldargs, tree newargs)                                              in pt.c

3901   {

3902     int ;

3903  

3904     if (TREE_VEC_LENGTH (oldargs) != TREE_VEC_LENGTH (newargs))

3905       return 0;

3906  

3907     for (i = 0; i < TREE_VEC_LENGTH (oldargs); ++i)

3908     {

3909       tree nt = TREE_VEC_ELT (newargs, i);

3910       tree ot = TREE_VEC_ELT (oldargs, i);

3911  

3912       if (! template_args_equal (ot, nt))

3913         return 0;

3914     }

3915     return 1;

3916   }

 

检查模板参数的相同性与检查树节点相同性的方法一致。

 

3879   static int

3880   template_args_equal (tree ot, tree nt)                                                                 in pt.c

3881   {

3882     if (nt == ot)

3883       return 1;

3884  

3885     if (TREE_CODE (nt) == TREE_VEC)

3886       /* For member templates */

3887       return TREE_CODE (ot) == TREE_VEC && comp_template_args (ot, nt);

3888     else if (TYPE_P (nt))

3889       return TYPE_P (ot) && same_type_p (ot, nt);

3890     else if (TREE_CODE (ot) == TREE_VEC || TYPE_P (ot))

3891       return 0;

3892     else

3893       return cp_tree_equal (ot, nt);

3894   }

 

上面的代码处理非具现的情形,在 4388 行的 return 语句结束。那么对于具现的情形,首先需要检查类似的具现已经处理了(一旦处理完,它就被记录在 DECL_TEMPLATE_INSTANTIATIONS 指向的链表中)。

 

lookup_template_class (continue)

 

4390       for (tp = &DECL_TEMPLATE_INSTANTIATIONS (template);

4391          *tp;

4392          tp = &TREE_CHAIN (*tp))

4393         if (comp_template_args (TREE_PURPOSE (*tp), arglist))

4394         {

              …

4405         }

4406  

4407       /* This type is a "partial instantiation" if any of the template

4408         arguments still involve template parameters. Note that we set

4409         IS_PARTIAL_INSTANTIATION for partial specializations as

4410         well.  */

4411       is_partial_instantiation = uses_template_parms (arglist);

4412  

4413       /* If the deduced arguments are invalid, then the binding

4414         failed.  */

4415       if (!is_partial_instantiation

4416          && check_instantiated_args (template,

4417                                  INNERMOST_TEMPLATE_ARGS (arglist),

4418                                  complain))

4419         POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, error_mark_node);

4420       

4421       if (!is_partial_instantiation

4422          && !PRIMARY_TEMPLATE_P (template)

4423          && TREE_CODE (CP_DECL_CONTEXT (template)) == NAMESPACE_DECL)

4424       {

            …

4429       }

4430        

4431       context = tsubst (DECL_CONTEXT (template), arglist,

4432                     complain, in_decl);

4433       if (!context)

4434         context = global_namespace ;

 

4412 行, uses_template_args 返回 0 来表示一个模板具现。在具现时刻,对于类型参数,它必须不能是可变大小的,比如语句:

struct S { int i[f()]; }

GNU C 中是有效的。而对于非类型参数,它必须是一个整形或枚举型常量。这个条件由 check_instantiated_args 来验证。

 

8705   static bool

8706   check_instantiated_args (tree tmpl, tree args, tsubst_flags_t complain)                in pt.c

8707   {

8708     int ix, len = DECL_NTPARMS (tmpl);

8709     bool result = false;

8710  

8711     for (ix = 0; ix != len; ix++)

8712     {

8713       tree t = TREE_VEC_ELT (args, ix);

8714      

8715       if (TYPE_P (t))

8716       {

8717          /* [basic.link]: A name with no linkage (notably, the name

8718           of a class or enumeration declared in a local scope)

8719           shall not be used to declare an entity with linkage.

8720           This implies that names with no linkage cannot be used as

8721            template arguments.  */

8722         tree nt = no_linkage_check (t);

8723  

8724         if (nt)

8725         {

8726           if (!(complain & tf_error))

8727              /*OK*/;

8728           else if (TYPE_ANONYMOUS_P (nt))

8729             error ("`%T' uses anonymous type", t);

8730           else

8731             error ("`%T' uses local type `%T'", t, nt);

8732           result = true;

8733         }

8734         /* In order to avoid all sorts of complications, we do not

8735           allow variably-modified types as template arguments.  */

8736         else if (variably_modified_type_p (t))

8737         {

8738           if (complain & tf_error)

8739             error ("`%T' is a variably modified type", t);

8740           result = true;

8741         }

8742       }

8743       /* A non-type argument of integral or enumerated type must be a

8744         constant.  */

8745       else if (TREE_TYPE (t)

8746             && INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (t))

8747             && !TREE_CONSTANT (t))

8748       {

8749         if (complain & tf_error)

8750           error ("integral expression `%E' is not constant", t);

8751         result = true;

8752       }

8753     }

8754     if (result && complain & tf_error)

8755       error ("  trying to instantiate `%D'", tmpl);

8756     return result;

8757   }

 

8722 行,如果类型依赖于一个不具有链接性类型, no_linkage_check 返回它;否则返回 NULL 。而对于这样的类型,它不能被用作模板具现的实参。一个类型是否具有可变大小则由下面的 variably_modified_type_p 来检查。

 

4316   bool

4317   variably_modified_type_p (tree type)                                                                in tree.c

4318   {

4319     tree t;

4320  

4321     if (type == error_mark_node)

4322       return false;

4323  

4324     /* If TYPE itself has variable size, it is variably modified.

4325  

4326       We do not yet have a representation of the C99 '[*]' syntax.

4327       When a representation is chosen, this function should be modified

4328       to test for that case as well.  */

4329     t = TYPE_SIZE (type);

4330     if (t && t != error_mark_node && TREE_CODE (t) != INTEGER_CST)

4331       return true;

4332  

4333     switch (TREE_CODE (type))

4334     {

4335       case POINTER_TYPE:

4336       case REFERENCE_TYPE:

4337       case ARRAY_TYPE:

4338         /* If TYPE is a pointer or reference, it is variably modified if

4339            the type pointed to is variably modified. Similarly for arrays;

4340            note that VLAs are handled by the TYPE_SIZE check above.  */

4341         return variably_modified_type_p (TREE_TYPE (type));

4342  

4343       case FUNCTION_TYPE:

4344       case METHOD_TYPE:

4345         /* If TYPE is a function type, it is variably modified if any of the

4346           parameters or the return type are variably modified.  */

4347         {

4348           tree parm;

4349  

4350           if (variably_modified_type_p (TREE_TYPE (type)))

4351             return true;

4352           for (parm = TYPE_ARG_TYPES (type);

4353               parm && parm != void_list_node;

4354               parm = TREE_CHAIN (parm))

4355             if (variably_modified_type_p (TREE_VALUE (parm)))

4356               return true;

4357         }

4358         break ;

4359  

4360       case INTEGER_TYPE:

4361          /* Scalar types are variably modified if their end points

4362           aren't constant.  */

4363         t = TYPE_MIN_VALUE (type);

4364         if (t && t != error_mark_node && TREE_CODE (t) != INTEGER_CST)

4365           return true;

4366         t = TYPE_MAX_VALUE (type);

4367         if (t && t != error_mark_node && TREE_CODE (t) != INTEGER_CST)

4368           return true;

4369         return false;

4370  

4371       default :

4372         break ;

4373     }

4374  

4375     /* The current language may have other cases to check, but in general,

4376       all other types are not variably modified.  */

4377     return (*lang_hooks .tree_inlining.var_mod_type_p ) (type);

4378   }

 

一个类型是否可变大小由其 TYPE_SIZE 域显示。如果这个域里的是一个 INTEGER_CST ,就是大小不可变的。因此对于可能包含可变大小的类型,它需要被一级一级地查找。对于 C++ 语言,方法是需要额外考虑的类型, 4377 行的钩子 var_mod_type_p 覆盖了这个情形。而它调用了下面的 cp_var_mod_type_p

 

381    static bool

382    cp_var_mod_type_p (tree type)                                                                       in cp-lang.c

383    {

384      /* If TYPE is a pointer-to-member, it is variably modified if either

385        the class or the member are variably modified.  */

386      if (TYPE_PTR_TO_MEMBER_P (type))

387        return (variably_modified_type_p (TYPE_PTRMEM_CLASS_TYPE (type))

388              || variably_modified_type_p(TYPE_PTRMEM_POINTED_TO_TYPE (type)));

389   

390      /* All other types are not variably modified.  */

391      return false;

392    }

 

对于我们的模板具现实参,它们成功地通过了这个测试。

4431 和, template 指向“ SmallObject ”的 TEMPLATE_DECL ,它被包含在名字空间“ Loki ”中。因此在 4431 行的 tsubst 只是返回对应的 NAMESPACE_DECL 而不做处理。

 

lookup_template_class (continue)

 

4436       /* Create the type.  */

4437       if (TREE_CODE (template_type) == ENUMERAL_TYPE)

4438       {

            …

4450       }

4451       else

4452       {

4453         t = make_aggr_type (TREE_CODE (template_type));

4454         CLASSTYPE_DECLARED_CLASS (t)

4455             = CLASSTYPE_DECLARED_CLASS (template_type);

4456         SET_CLASSTYPE_IMPLICIT_INSTANTIATION (t);

4457         TYPE_FOR_JAVA (t) = TYPE_FOR_JAVA (template_type);

4458  

4459         /* A local class. Make sure the decl gets registered properly.  */

4460         if (context == current_function_decl )

4461            pushtag (DECL_NAME (template), t, 0);

4462       }

4463  

4464        /* If we called start_enum or pushtag above, this information

4465         will already be set up.  */

4466       if (!TYPE_NAME (t))

4467       {

4468         TYPE_CONTEXT (t) = FROB_CONTEXT (context);

4469         

4470         type_decl = create_implicit_typedef (DECL_NAME (template), t);

4471         DECL_CONTEXT (type_decl) = TYPE_CONTEXT (t);

4472         TYPE_STUB_DECL (t) = type_decl;

4473         DECL_SOURCE_LOCATION (type_decl)

4474            = DECL_SOURCE_LOCATION (TYPE_STUB_DECL (template_type));

4475       }

4476       else

4477         type_decl = TYPE_NAME (t);

4478  

4479       TREE_PRIVATE (type_decl)

4480          = TREE_PRIVATE (TYPE_STUB_DECL (template_type));

4481       TREE_PROTECTED (type_decl)

4482          = TREE_PROTECTED (TYPE_STUB_DECL (template_type));

4483  

4484       /* Set up the template information. We have to figure out which

4485         template is the immediate parent if this is a full

4486         instantiation.  */

4487       if (parm_depth == 1 || is_partial_instantiation

4488          || !PRIMARY_TEMPLATE_P (template))

4489         /* This case is easy; there are no member templates involved.  */

4490         found = template;

4491       else

4492       {

             …

4544       }

4545  

4546       SET_TYPE_TEMPLATE_INFO (t, tree_cons (found, arglist, NULL_TREE)); 

4547       DECL_TEMPLATE_INSTANTIATIONS (template)

4548            = tree_cons (arglist, t,

4549                       DECL_TEMPLATE_INSTANTIATIONS (template));

4550  

4551       if (TREE_CODE (t) == ENUMERAL_TYPE

4552          && !is_partial_instantiation)

4553         /* Now that the type has been registered on the instantiations

4554           list, we set up the enumerators. Because the enumeration

4555           constants may involve the enumeration type itself, we make

4556           sure to register the type first, and then create the

4557           constants. That way, doing tsubst_expr for the enumeration

4558           constants won't result in recursive calls here; we'll find

4559           the instantiation and exit above.  */

4560         tsubst_enum (template_type, t, arglist);

4561  

4562       /* Reset the name of the type, now that CLASSTYPE_TEMPLATE_INFO

4563         is set up.  */

4564       if (TREE_CODE (t) != ENUMERAL_TYPE)

4565         DECL_NAME (type_decl) = classtype_mangled_name (t);

4566       if (is_partial_instantiation)

4567         /* If the type makes use of template parameters, the

4568           code that generates debugging information will crash.  */

4569          DECL_IGNORED_P (TYPE_STUB_DECL (t)) = 1;

4570  

4571       POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, t);

4572     }

4573     timevar_pop (TV_NAME_LOOKUP);

4574   }

 

对于新的具现(例如我们的例子),一个 RECORD_TYPE 及关联的节点被构建,因为每次具现都引入一个新的类型。为了防止重复定义,每个具现都被 4247 行的 DECL_TEMPLATE_INSTANTIATIONS 所记录;不过这只在同一个编译单元中可用。这种方式不能避免跨编译单元的重复定义,但是链接器可以有所帮助。在函数的退出点,我们得到以下的中间树(新节点以蓝色显示)。

点此打开

上图中的 RECORD_TYPE 节点是由 lookup_template_class 返回的,而通过其 chain 域访问的 TYPE_DECL 则由 finish_template_type 返回。这个 TYPE_DECL cp_parser_template_id 7997 行用作 template_id 的结果,然后在下面 cp_parser_class_name 中返回作 decl

 

cp_parser_class_name (continue)

 

11812   decl = cp_parser_maybe_treat_template_as_class (decl, class_head_p);

11813

11814   /* If this is a typename, create a TYPENAME_TYPE.  */

11815   if (typename_p && decl != error_mark_node)

11816   {

11817     decl = make_typename_type (scope, decl, /*complain=*/ 1);

11818     if (decl != error_mark_node)

11819       decl = TYPE_NAME (decl);

11820   }

11821

11822   /* Check to see that it is really the name of a class.  */

11823   if (TREE_CODE (decl) == TEMPLATE_ID_EXPR

11824      && TREE_CODE (TREE_OPERAND (decl, 0)) == IDENTIFIER_NODE

11825      && cp_lexer_next_token_is (parser->lexer, CPP_SCOPE))

11826     /* Situations like this:

11827

11828       template <typename T> struct A {

11829         typename T::template X<int>::I i;

11830       };

11831

11832       are problematic. Is `T::template X<int>' a class-name? The

11833       standard does not seem to be definitive, but there is no other

11834       valid interpretation of the following `::'. Therefore, those

11835       names are considered class-names.  */

11836     decl = TYPE_NAME (make_typename_type (scope, decl, tf_error));

11837   else if (decl == error_mark_node

11838         || TREE_CODE (decl) != TYPE_DECL

11839         || !IS_AGGR_TYPE (TREE_TYPE (decl)))

11840   {

11841     cp_parser_error (parser, "expected class-name");

11842     return error_mark_node;

11843   }

11844

11845   return decl;

11846 }

 

11812 行, cp_parser_maybe_treat_template_as_class 不对传入 TYPE_DECL 做任何事,只是返回对应的 TYPE_DECL ,如果它是 TEMPALTE_DECL 。因此 decl 也被 cp_parser_class_name 返回。事实上这个 TYPE_DECL 正是我们在 decl-specifier-seq 中查找的 type-specifier 。这个节点一直返回到 cp_parser_simple_declaration

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值