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

 

5.12.4.2.3.        处理基类
5.12.4.2.3.1.  解析 base-clause

SmallObject ”后的符号是:“ : public ThreadingModel<SmallObject<ThreadingModel, chunkSize, maxSmallObjectSize> > ”,它们表示了“ SmallObject ”所派生的基类。 class-head 的规则重现如下。

class-head:

   class-key identifier [opt] base-clause [opt]

   class-key nested-name-specifier identifier base-clause [opt]

   class-key nested-name-specifier [opt] template-id base-clause [opt]

如果 nested-name-specifier 出现,下面的变量 nested_name_specifier 将指向其树节点。毫无疑问,它构成了一个上下文,基类在其中应是可见的。那么在下面的 12330 行,如果 nested_name_specifier 不是 null ,它由 push_scope 设置为当前作用域。

 

cp_parser_class_head (continue)

 

12317   /* Indicate whether this class was declared as a `class' or as a

12318     `struct'.  */

12319   if (TREE_CODE (type) == RECORD_TYPE)

12320     CLASSTYPE_DECLARED_CLASS (type) = (class_key == class_type);

12321   cp_parser_check_class_key (class_key, type);

12322

12323   /* Enter the scope containing the class; the names of base classes

12324     should be looked up in that context. For example, given:

12325

12326       struct A { struct B {}; struct C; };

12327       struct A::C : B {};

12328

12329     is valid.  */

12330   if (nested_name_specifier)

12331     pop_p = push_scope (nested_name_specifier);

12332   /* Now, look for the base-clause.  */

12333   token = cp_lexer_peek_token (parser->lexer);

12334   if (token->type == CPP_COLON)

12335   {

12336     tree bases;

12337

12338     /* Get the list of base-classes.  */

12339     bases = cp_parser_base_clause (parser);

12340      /* Process them.  */

12341     xref_basetypes (type, bases);

12342   }

12343   /* Leave the scope given by the nested-name-specifier. We will

12344     enter the class scope itself while processing the members.  */

12345   if (pop_p)

12346     pop_scope (nested_name_specifier);

12347

12348 done:

12349   if (invalid_explicit_specialization_p)

12350   {

12351     end_specialization ();

12352     --parser->num_template_parameter_lists;

12353   }

12354   *attributes_p = attributes;

12355   return type;

12356 }

 

事实上,由“ : ”开头的部分,根据语法,被称为 base-clause ,它遵守如下的规则:

base-clause:

   : base-specifier-list 

base-specifier-list:

   base-specifier

   base-specifier-list , base-specifier

显然,如果 base-specifier-list 包含了多于一个基类描述符( base-specifier ),它对应于多继承。而且这些基类被在下面函数中的变量 bases 串接起来。

 

12900 static tree

12901 cp_parser_base_clause (cp_parser* parser)                                               in parser.c

12902 {

12903   tree bases = NULL_TREE;

12904

12905   /* Look for the `:' that begins the list.  */

12906   cp_parser_require (parser, CPP_COLON, "`:'");

12907

12908   /* Scan the base-specifier-list.  */

12909   while (true)

12910   {

12911     cp_token *token;

12912     tree base;

12913

12914     /* Look for the base-specifier.  */

12915     base = cp_parser_base_specifier (parser);

12916      /* Add BASE to the front of the list.  */

12917     if (base != error_mark_node)

12918     {

12919       TREE_CHAIN (base) = bases;

12920       bases = base;

12921     }

12922     /* Peek at the next token.  */

12923     token = cp_lexer_peek_token (parser->lexer);

12924     /* If it's not a comma, then the list is complete.  */

12925     if (token->type != CPP_COMMA)

12926       break ;

12927     /* Consume the `,'.   */

12928     cp_lexer_consume_token (parser->lexer);

12929   }

12930

12931   /* PARSER->SCOPE may still be non-NULL at this point, if the last

12932     base class had a qualified name. However, the next name that

12933     appears is certainly not qualified.  */

12934   parser->scope = NULL_TREE;

12935   parser->qualifying_scope = NULL_TREE;

12936   parser->object_scope = NULL_TREE;

12937

12938   return nreverse (bases);

12939 }

 

base-specifier 部分描述了从谁及如何派生。因此其规则如下。

base-specifier:

   :: [opt] nested-name-specifier [opt] class-name

   virtual access-specifier [opt] :: [opt] nested-name-specifier [opt] class-name

   access-specifier virtual [opt] :: [opt] nested-name-specifier [opt] class-name

 

12955 static tree

12956 cp_parser_base_specifier (cp_parser* parser)                                            in parser.c

12957 {

12958   cp_token *token;

12959   bool done = false;

12960   bool virtual_p = false;

12961   bool duplicate_virtual_error_issued_p = false;

12962   bool duplicate_access_error_issued_p = false;

12963   bool class_scope_p, template_p;

12964   tree access = access_default_node;

12965   tree type;

12966

12967   /* Process the optional `virtual' and `access-specifier'.  */

12968   while (!done)

12969   {

12970     /* Peek at the next token.  */

12971     token = cp_lexer_peek_token (parser->lexer);

12972     /* Process `virtual'.  */

12973     switch (token->keyword)

12974     {

12975       case RID_VIRTUAL:

12976          /* If `virtual' appears more than once, issue an error.  */

12977         if (virtual_p && !duplicate_virtual_error_issued_p)

12978         {

12979           cp_parser_error (parser,

12980                         "`virtual' specified more than once in base-specified");

12981           duplicate_virtual_error_issued_p = true;

12982         }

12983

12984         virtual_p = true;

12985

12986         /* Consume the `virtual' token.  */

12987         cp_lexer_consume_token (parser->lexer);

12988

12989         break ;

12990

12991       case RID_PUBLIC:

12992       case RID_PROTECTED:

12993       case RID_PRIVATE:

12994         /* If more than one access specifier appears, issue an

12995           error.  */

12996         if (access != access_default_node

12997             && !duplicate_access_error_issued_p)

12998         {

12999           cp_parser_error (parser,

13000                         "more than one access specifier in base-specified");

13001           duplicate_access_error_issued_p = true;

13002         }

13003

13004         access = ridpointers [(int) token->keyword];

13005

13006          /* Consume the access-specifier.  */

13007         cp_lexer_consume_token (parser->lexer);

13008

13009         break ;

13010

13011       default :

13012         done = true;

13013         break ;

13014     }

13015   }

13016   /* It is not uncommon to see programs mechanically, errouneously, use

13017     the 'typename' keyword to denote (dependent) qualified types

13018     as base classes.  */

13019   if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TYPENAME))

13020   {

13021     if (!processing_template_decl)

13022       error ("keyword `typename' not allowed outside of templates");

13023     else

13024       error ("keyword `typename' not allowed in this context "

13025            "(the base class is implicitly a type)");

13026       cp_lexer_consume_token (parser->lexer);

13027   }

13028

13029   /* Look for the optional `::' operator.  */

13030   cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/ false);

13031   /* Look for the nested-name-specifier. The simplest way to

13032     implement:

13033

13034       [temp.res]

13035

13036     The keyword `typename' is not permitted in a base-specifier or

13037     mem-initializer; in these contexts a qualified name that

13038     depends on a template-parameter is implicitly assumed to be a

13039     type name.

13040

13041     is to pretend that we have seen the `typename' keyword at this

13042     point.  */

13043   cp_parser_nested_name_specifier_opt (parser,

13044                                   /*typename_keyword_p=*/ true,

13045                                   /*check_dependency_p=*/ true,

13046                                    /*type_p=*/ true,

13047                                   /*is_declaration=*/ true);

13048   /* If the base class is given by a qualified name, assume that names

13049     we see are type names or templates, as appropriate.  */

13050   class_scope_p = (parser->scope && TYPE_P (parser->scope));

13051   template_p = class_scope_p && cp_parser_optional_template_keyword (parser);

13052  

13053   /* Finally, look for the class-name.  */

13054   type = cp_parser_class_name (parser,

13055                           class_scope_p,

13056                           template_p,

13057                           /*type_p=*/ true,

13058                           /*check_dependency_p=*/ true,

13059                           /*class_head_p=*/ false,

13060                           /*is_declaration=*/ true);

13061

13062   if (type == error_mark_node)

13063     return error_mark_node;

13064

13065   return finish_base_specifier (TREE_TYPE (type), access, virtual_p);

13066 }

 

上面, cp_parser_nested_name_specifier_opt parser scope 设置为 nested-name-specifier 如果出现的话,这又相应地影响类名查找的结果。在 13051 行, cp_parser_optional_template_keyword 检查关键字“ template ”是否出现,如果出现并且 nested-name-specifier 表示一个类作用域,它是一个模板名的明示。对于我们例子, template_p false 。类名查找的细节在前面已经给出。

简而言之,类“ ThreadingModel ”已经被声明了,在 8212 行是 cp_parser_template_name 中, cp_parser_lookup_name 返回相应的 TEMPLATE_DECL 。有趣的是,模板实参“ SmallObject<ThreadingModel, chunkSize, maxSmallObjectSize> ”又是 template-id 。因此这个名字沿着 cp_parser_enclosed_template_argument_list cp_parser_template_argument_list cp_parser_template_argument cp_parser_id_expression cp_parser_unqualified_id cp_parser_template_id ,再一次加入在 8212 行的 cp_parser_template_name ,找出“ SmallObject ”的 TEMPLATE_DECL (因为类的标签已经被处理了),然后在 7899 行的 cp_parser_template_id 中,递归进入 cp_parser_enclosed_template_argument_list

5.12.4.2.3.1.1.          内层 template-id

这一次“ ThreadingModel ”是一个 type-id ,由如下调用栈解析: cp_parser_type_id cp_parser_type_specifier_seq cp_parser_type_specifier cp_parser_simple_type_specifier cp_parser_type_name ,在 11795 行的 cp_parser_class_name 中,同样的 cp_parser_lookup_name 返回对应的 TEMPLATE_DECL ,而在 11812 行的 cp_parser_maybe_treat_template_as_class TEMPLATE_DECL result 域提取对应的 TYPE_DECL 。然后在 cp_parser_type_id 10947 行, groktypename 向这个 TYPE_DECL type 域填入相应的 TEMPLATE_TEMPLATE_PARM

接下来“ chunkSize ”及“ maxSmallObjectSize ”都是从 assignment-expression 降下来的 id-expression 。它们的 IDENTIFIER_NODE 作为结果返回。那么在 cp_parser_template_id 7994 行,因为 template TEMPLATE_DECL template-id 需要由下面的 finish_template_type 来构建。

 

cp_parser_template_id

 

7991     /* Build a representation of the specialization.  */

7992     if (TREE_CODE (template) == IDENTIFIER_NODE)

7993       template_id = build_min_nt (TEMPLATE_ID_EXPR, template, arguments);

7994     else if (DECL_CLASS_TEMPLATE_P (template)

7995           || DECL_TEMPLATE_TEMPLATE_PARM_P (template))

7996       template_id

7997         = finish_template_type (template, arguments,

7998                             cp_lexer_next_token_is (parser->lexer,

7999                                                  CPP_SCOPE));

 

这里 arguments tree_vec 形式的模板实参列表。

t

 

2222   tree

2223   finish_template_type (tree name, tree args, int entering_scope)              in semantics.c

2224   {

2225     tree decl;

2226  

2227     decl = lookup_template_class (name, args,

2228                             NULL_TREE, NULL_TREE, entering_scope,

2229                             tf_error | tf_warning | tf_user);

2230     if (decl != error_mark_node)

2231       decl = TYPE_STUB_DECL (decl);

2232  

2233     return decl;

2234   }

 

同样参数 name 指向的“ SmallObject ”的 TEMPLATE_DECL 显示如下。当类“ SmallObject ”的类标签得到处理后,我们期望看到这样的树,注意到为了不使图太大,最后的参数“ std::size_t maxSmallObjectSize ”没有显示出来,因为我们可以看到几乎相同的参数“ std::size_t chunkSize ”。

点此打开

110 :类标签处理后的 SmallObject

而在这次调用中,参数 in_decl context 都是 NULL ,而 entering_scope 0

 

4133   tree

4134   lookup_template_class (tree d1,                                                                              in pt.c

4135                       tree arglist,

4136                       tree in_decl,

4137                       tree context,

4138                       int entering_scope,

4139                       tsubst_flags_t complain)

4140   {

4141     tree template = NULL_TREE, parmlist;

4142     tree t;

4143    

4144     timevar_push (TV_NAME_LOOKUP);

4145    

4146     if (TREE_CODE (d1) == IDENTIFIER_NODE)

4147     {

4148       if (IDENTIFIER_VALUE (d1)

4149           && DECL_TEMPLATE_TEMPLATE_PARM_P (IDENTIFIER_VALUE (d1)))

4150         template = IDENTIFIER_VALUE (d1);

4151       else

4152       {

4153           if (context)

4154             push_decl_namespace (context);

4155          template = lookup_name (d1, /*prefer_type=*/ 0);

4156           template = maybe_get_template_decl_from_type_decl (template);

4157           if (context)

4158             pop_decl_namespace ();

4159       }

4160       if (template)

4161         context = DECL_CONTEXT (template);

4162     }

4163     else if (TREE_CODE (d1) == TYPE_DECL && IS_AGGR_TYPE (TREE_TYPE (d1)))

4164     {

4165       tree type = TREE_TYPE (d1);

4166  

4167       /* If we are declaring a constructor, say A<T>::A<T>, we will get

4168         an implicit typename for the second A. Deal with it.  */

4169       if (TREE_CODE (type) == TYPENAME_TYPE && TREE_TYPE (type))

4170       type = TREE_TYPE (type);

4171       

4172        if (CLASSTYPE_TEMPLATE_INFO (type))

4173       {

4174          template = CLASSTYPE_TI_TEMPLATE (type);

4175          d1 = DECL_NAME (template);

4176       } 

4177     }

4178     else if (TREE_CODE (d1) == ENUMERAL_TYPE

4179           || (TYPE_P (d1) && IS_AGGR_TYPE (d1)))

4180     {

4181       template = TYPE_TI_TEMPLATE (d1);

4182       d1 = DECL_NAME (template);

4183     }

4184     else if (TREE_CODE (d1) == TEMPLATE_DECL

4185           && TREE_CODE (DECL_TEMPLATE_RESULT (d1)) == TYPE_DECL)

4186     {

4187       template = d1;

4188       d1 = DECL_NAME (template);

4189       context = DECL_CONTEXT (template);

4190     }

4191  

4192     /* With something like `template <class T> class X class X { ... };'

4193       we could end up with D1 having nothing but an IDENTIFIER_VALUE.

4194       We don't want to do that, but we have to deal with the situation,

4195       so let's give them some syntax errors to chew on instead of a

4196       crash. Alternatively D1 might not be a template type at all.  */

4197     if (! template)

4198     {

4199       if (complain & tf_error)

4200         error ("`%T' is not a template", d1);

4201       POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, error_mark_node);

4202     }

4203  

4204     if (TREE_CODE (template) != TEMPLATE_DECL

4205        /* Make sure it's a user visible template, if it was named by

4206          the user.  */

4207        || ((complain & tf_user) && !DECL_TEMPLATE_PARM_P (template)

4208           && !PRIMARY_TEMPLATE_P (template)))

4209     {

4210       if (complain & tf_error)

4211       {

4212         error ("non-template type `%T' used as a template", d1);

4213         if (in_decl)

4214           cp_error_at ("for template declaration `%D'", in_decl);

4215       }

4216       POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, error_mark_node);

4217     }

4218  

4219     complain &= ~tf_user;

 

上面 template 4187 行被更新作“ SmallObject ”的 TEMPLATE_DECL dl 被更新为相应的 IDENTIFIER_NODE 节点,而 context 则是 NULL 。并且下面的 template_type 被设置为 TEMPLATE_TEMPLATE_PARM 节点;那么在 4271 行的 most_general_template 返回该模板最泛化的声明( most-general declaration ,对于我们的例子,该模板就是最泛化的形式)。遍历上图中的模板实参,得到 parm_depth 1 arg_depth 1 arglist 就是上图中的 arguments )。

由其名字所显示, arg_depth 对应于该 template-id 实参的深度,而 parm_depth 是对应模板声明参数的深度。两者不相同的例子如下所示:

template <class T> struct S1 {

    template <class U> struct S2 {};

};

S2 的声明中,实参列表是“ U ”,但其完整的定义(如果定义在 S1 外部)是: template <class T> template <U> struct S1<T>::S2

这正是解析器所期望的!它必须填入缺失的实参“ T ”。不过,我们没有这个麻烦,我们可以跳过它。

 

lookup_template_class (continue)

 

4221     if (DECL_TEMPLATE_TEMPLATE_PARM_P (template))

4222     {

          …

4259     }

4260     else

4261     {

4262       tree template_type = TREE_TYPE (template);

4263       tree gen_tmpl;

4264       tree type_decl;

4265       tree found = NULL_TREE;

4266       tree *tp;

4267       int arg_depth;

4268       int parm_depth;

4269       int is_partial_instantiation;

4270  

4271       gen_tmpl = most_general_template (template);

4272       parmlist = DECL_TEMPLATE_PARMS (gen_tmpl);

4273       parm_depth = TMPL_PARMS_DEPTH (parmlist);

4274       arg_depth = TMPL_ARGS_DEPTH (arglist);

4275  

4276       if (arg_depth == 1 && parm_depth > 1)

4277       {

4278          /* We've been given an incomplete set of template arguments.

4279             For example, given:

4280  

4281            template <class T> struct S1 {

4282             template <class U> struct S2 {};

4283              template <class U> struct S2<U*> {};

4284           };

4285            

4286            we will be called with an ARGLIST of `U*', but the

4287            TEMPLATE will be `template <class T> template

4288            <class U> struct S1<T>::S2'. We must fill in the missing

4289            arguments.  */

4290          arglist

4291            = add_outermost_template_args (TYPE_TI_ARGS (TREE_TYPE (template)),

4292                                        arglist);

4293          arg_depth = TMPL_ARGS_DEPTH (arglist);

4294       }

4295  

4296       /* Now we should have enough arguments.  */

4297       my_friendly_assert (parm_depth == arg_depth, 0);

4298        

4299       /* From here on, we're only interested in the most general

4300         template.  */

4301       template = gen_tmpl;

4302  

4303       /* Calculate the BOUND_ARGS. These will be the args that are

4304         actually tsubst'd into the definition to create the

4305         instantiation.  */

4306       if (parm_depth > 1)

4307       {

            …

4344       }

4345       else

4346         arglist

4347             = coerce_template_parms (INNERMOST_TEMPLATE_PARMS (parmlist),

4348                                   INNERMOST_TEMPLATE_ARGS (arglist),

4349                                   template,

4350                                   complain, /*require_all_args=*/ 1);

 

在适当地加入额外的实参后, arg_depth 应该等于 parm_depth ,而 parm_depth 1 的情形表示正在处理类模板的成员。这不是我们的气数。在 4347 行, INNERMOST_TEMPLATE_PARMS 返回在上图 类标签处理后的 SmallObject 中的 TREE_VEC 节点,而 INNERMOST_TEMPLATE_ARGS 返回整个实参列表。

 

3805   static tree

3806   coerce_template_parms (tree parms,                                                                       in pt.c

3807                       tree args,

3808                       tree in_decl,

3809                       tsubst_flags_t complain,

3810                       int require_all_arguments)

3811   {

3812     int nparms, nargs, i, lost = 0;

3813     tree inner_args;

3814     tree new_args;

3815     tree new_inner_args;

3816  

3817     inner_args = INNERMOST_TEMPLATE_ARGS (args);

3818     nargs = inner_args ? NUM_TMPL_ARGS (inner_args) : 0;

3819     nparms = TREE_VEC_LENGTH (parms);

3820  

3821     if (nargs > nparms

3822       || (nargs < nparms

3823         && require_all_arguments

3824         && TREE_PURPOSE (TREE_VEC_ELT (parms, nargs)) == NULL_TREE))

3825     {

3826       if (complain & tf_error)

3827       {

3828         error ("wrong number of template arguments (%d, should be %d)",

3829               nargs, nparms);

3830         

3831         if (in_decl)

3832           cp_error_at ("provided for `%D'", in_decl);

3833       }

3834  

3835       return error_mark_node;

3836     }

 

上面的 3818 行, NUM_TMPL_ARGS 返回向量的 TREE_VEC_LENGTH 。看到在这一步,实参的数目不应该多于参数的数目。对于我们的声明,实参的数目是 3 ,与参数数目相同。现在 nparms 保存着这个数目。

 

coerce_template_parms (continue)

 

3838     new_inner_args = make_tree_vec (nparms);

3839     new_args = add_outermost_template_args (args, new_inner_args);

 

在参数数目多于实参数目的情形下,涉及到缺省实参的使用。这些缺省实参必须通过 add_outermost_template_args 添加进来。

 

538    static tree

539    add_outermost_template_args (tree args, tree extra_args)                                          in pt.c

540    {

541      tree new_args;

542   

543      /* If there are more levels of EXTRA_ARGS than there are ARGS,

544        something very fishy is going on.  */

545      my_friendly_assert (TMPL_ARGS_DEPTH (args) >= TMPL_ARGS_DEPTH (extra_args),

546                       0);

547   

548      /* If *all* the new arguments will be the EXTRA_ARGS, just return

549        them.  */

550      if (TMPL_ARGS_DEPTH (args) == TMPL_ARGS_DEPTH (extra_args))

551        return extra_args;

552   

553      /* For the moment, we make ARGS look like it contains fewer levels.  */

554      TREE_VEC_LENGTH (args) -= TMPL_ARGS_DEPTH (extra_args);

555     

556      new_args = add_to_template_args (args, extra_args);

557   

558      /* Now, we restore ARGS to its full dimensions.  */

559      TREE_VEC_LENGTH (args) += TMPL_ARGS_DEPTH (extra_args);

560   

561      return new_args;

562    }

 

对于没有使用缺省实参的情况, add_outermost_template_args 不作任何事只是把 new_inner_args 返回给 new_args 。现在 parms 是在上图 类标签处理后的 SmallObject 中的 TREE_VEC 节点;因此对于第一个成员, parm 指向下面的节点。

t2

 

coerce_template_parms (continue)

 

3840     for (i = 0; i < nparms; i++)

3841     {

3842       tree arg;

3843       tree parm;

3844  

3845       /* Get the Ith template parameter.  */

3846       parm = TREE_VEC_ELT (parms, i);

3847  

3848       /* Calculate the Ith argument.  */

3849       if (i < nargs)

3850         arg = TREE_VEC_ELT (inner_args, i);

3851       else if (require_all_arguments)

3852         /* There must be a default arg in this case.  */

3853         arg = tsubst_template_arg (TREE_PURPOSE (parm), new_args,

3854                               complain, in_decl);

3855       else

3856          break ;

3857        

3858       my_friendly_assert (arg, 20030727);

3859       if (arg == error_mark_node)

3860         error ("template argument %d is invalid", i + 1);

3861       else

3862         arg = convert_template_argument (TREE_VALUE (parm),

3863                                     arg, new_args, complain, i,

3864                                     i n_decl);

3865        

3866       if (arg == error_mark_node)

3867         lost++;

3868       TREE_VEC_ELT (new_inner_args, i) = arg;

3869     }

3870  

3871     if (lost)

3872       return error_mark_node;

3873  

3874     return new_inner_args;

3875   }

 

在这次调用中,实参 parm 是“ ThreadingModel ”的 TEMPLATE_DECL arg 也是指向这个节点。上面因为 nargs naprms 相等, arg inner_args 获得。

 

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

3649  

3650     if (TREE_CODE (arg) == TREE_LIST

3651         && TREE_CODE (TREE_VALUE (arg)) == OFFSET_REF)

3652     { 

3653       /* The template argument was the name of some

3654         member function. That's usually

3655         invalid, but static members are OK. In any

3656         case, grab the underlying fields/functions

3657         and issue an error later if required.  */

3658       arg = TREE_VALUE (arg);

3659       TREE_TYPE (arg) = unknown_type_node;

3660     }

3661  

3662     requires_tmpl_type = TREE_CODE (parm) == TEMPLATE_DECL;

3663     requires_type = (TREE_CODE (parm) == TYPE_DECL

3664                   || requires_tmpl_type);

3665  

3666     is_tmpl_type = ((TREE_CODE (arg) == TEMPLATE_DECL

3667                   && TREE_CODE (DECL_TEMPLATE_RESULT (arg)) == TYPE_DECL)

3668                  || TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM

3669                   || TREE_CODE (arg) == UNBOUND_CLASS_TEMPLATE);

3670    

3671     if (is_tmpl_type

3672        && (TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM

3673             || TREE_CODE (arg) == UNBOUND_CLASS_TEMPLATE))

3674       arg = TYPE_STUB_DECL (arg);

3675  

3676     is_type = TYPE_P (arg) || is_tmpl_type;

 

显然,此处,我们有 requires_tmpl_type 1 ), requires_type 1 ), is_tmpl_type 1 ), is_type 1 )。在这些变量中,可以看到 requires_tmpl_type requires_type 的子集,同样的还有 is_tmpl_type is_type 。任何不一致都意味着错误!

 

convert_template_arguments (continue)

 

3678     if (requires_type && ! is_type && TREE_CODE (arg) == SCOPE_REF

3679         && TREE_CODE (TREE_OPERAND (arg, 0)) == TEMPLATE_TYPE_PARM)

3680     {

3681       pedwarn ("to refer to a type member of a template parameter, use `typename %E'", arg);

3682        

3683       arg = make_typename_type (TREE_OPERAND (arg, 0),

3684                              TREE_OPERAND (arg, 1),

3685                              complain & tf_error);

3686       is_type = 1;

3687     }

3688     if (is_type != requires_type)

3689     {

3690       if (in_decl)

3691       {

3692         if (complain & tf_error)

3693         {

3694           error ("type/value mismatch at argument %d in template parameter list for `%D'",

3695                i + 1, in_decl);

3696           if (is_type)

3697             error ("  expected a constant of type `%T', got `%T'",

3698                   TREE_TYPE (parm),

3699                   (is_tmpl_type ? DECL_NAME (arg) : arg));

3700           else if (requires_tmpl_type)

3701             error ("  expected a class template, got `%E'", arg);

3702           else

3703             error ("  expected a type, got `%E'", arg);

3704         }

3705       }

3706       return error_mark_node;

3707     }

3708     if (is_tmpl_type ^ requires_tmpl_type)

3709     {

3710       if (in_decl && (complain & tf_error))

3711       {

3712         error ("type/value mismatch at argument %d in template parameter list for `%D'",

3713              i + 1, in_decl);

3714         if (is_tmpl_type)

3715           error ("  expected a type, got `%T'", DECL_NAME (arg));

3716         else

3717           error ("  expected a class template, got `%T'", arg);

3718       }

3719       return error_mark_node;

3720     }

3721        

3722     if (is_type)

3723     {

3724       if (requires_tmpl_type)

3725       {

3726         if (TREE_CODE (TREE_TYPE (arg)) == UNBOUND_CLASS_TEMPLATE)

3727           /* The number of argument required is not known yet.

3728             Just accept it for now.  */

3729           val = TREE_TYPE (arg);

3730         else

3731         {

3732           tree parmparm = DECL_INNERMOST_TEMPLATE_PARMS (parm);

3733           tree argparm = DECL_INNERMOST_TEMPLATE_PARMS (arg);

3734  

3735           if (coerce_template_template_parms (parmparm, argparm,

3736                                          complain, in_decl,

3737                                          inner_args))

3738           {

3739             val = arg;

3740                

3741             /* TEMPLATE_TEMPLATE_PARM node is preferred over

3742               TEMPLATE_DECL.  */

3743             if (val != error_mark_node

3744                && DECL_TEMPLATE_TEMPLATE_PARM_P (val))

3745               val = TREE_TYPE (val);

3746           }

3747           else

3748           {

3749             if (in_decl && (complain & tf_error))

3750             {

3751               error ("type/value mismatch at argument %d in template parameter list for `%D'",

3752                     i + 1, in_decl);

3753               error ("  expected a template of type `%D', got `%D'", parm, arg);

3754             }

3755                

3756             val = error_mark_node;

3757           }

3758         }

3759       }

3760       else

3761         val = groktypename (arg);

3762     }

3763     else

3764     {

          …

3790     }

3791  

3792     return val;

3793   }

5.12.4.2.3.1.1.1.    模板模板实参

因为 parm arg 指向同一个 TEMPALTE_DECL ,那么 parmparm argparm 都指向下图中的 TREE_VEC ,这个节点来自“ ThreadingModel ”的 TEMPLATE_DECL

点此打开

 

3559   static int

3560   coerce_template_template_parms (tree parm_parms,                                          in pt.c

3561                               tree arg_parms,

3562                               tsubst_flags_t complain,

3563                               tree in_decl,

3564                               tree outer_args)

3565   {

3566     int nparms, nargs, i;

3567     tree parm, arg;

3568  

3569     my_friendly_assert (TREE_CODE (parm_parms) == TREE_VEC, 0);

3570     my_friendly_assert (TREE_CODE (arg_parms) == TREE_VEC, 0);

3571  

3572     nparms = TREE_VEC_LENGTH (parm_parms);

3573     nargs = TREE_VEC_LENGTH (arg_parms);

3574  

3575     /* The rule here is opposite of coerce_template_parms.  */

3576     if (nargs < nparms

3577        || (nargs > nparms

3578          && TREE_PURPOSE (TREE_VEC_ELT (arg_parms, nparms)) == NULL_TREE))

3579       return 0;

3580  

3581     for (i = 0; i < nparms; ++i)

3582     {

3583       parm = TREE_VALUE (TREE_VEC_ELT (parm_parms, i));

3584       arg = TREE_VALUE (TREE_VEC_ELT (arg_parms, i));

3585  

3586       if (arg == NULL_TREE || arg == error_mark_node

3587          || parm == NULL_TREE || parm == error_mark_node)

3588         return 0;

3589  

3590       if (TREE_CODE (arg) != TREE_CODE (parm))

3591         return 0;

3592  

3593       switch (TREE_CODE (parm))

3594       {

3595         case TYPE_DECL:

3596           break ;

3597  

3598         case TEMPLATE_DECL:

3599           /* We encounter instantiations of templates like

3600             template <template <template <class> class> class TT>

3601             class C;  */

3602         {

3603           tree parmparm = DECL_INNERMOST_TEMPLATE_PARMS (parm);

3604           tree argparm = DECL_INNERMOST_TEMPLATE_PARMS (arg);

3605  

3606           if (!coerce_template_template_parms

3607              (parmparm, argparm, complain, in_decl, outer_args))

3608             return 0;

3609         }

3610         break ;

3611  

3612         case PARM_DECL:

3613           /* The tsubst call is used to handle cases such as

3614             template <class T, template <T> class TT> class D; 

3615              i.e. the parameter list of TT depends on earlier parameters.  */

3616           if (!same_type_p

3617              (tsubst (TREE_TYPE (parm), outer_args, complain, in_decl),

3618                     TREE_TYPE (arg)))

3619             return 0;

3620           break ;

3621         

3622         default :

3623           abort ();

3624       }

3625     }

3626     return 1;

3627   }

 

类型完全匹配的 parm_parms arg_parms 使得函数返回 1 。这个函数,除了验证模板模板的实参及模板模板的参数之外,还将填入缺省实参。

然后在 coerce_template_arguments 3745 行, val 被更新为上图中的 TEMPLATE_TEMPLATE_PARM 节点。并且这个节点接下来被放入 new_inner_args 的第一个成员。

5.12.4.2.3.1.1.2.    非类型实参

对于第二个实参, coerce_template_arguments 的实参 arg 是“ chunkSize ”的 IDENTIFIER_NODE 节点,而 parm 则是在下图中标为红色的 value 所指向的节点。

点此打开

 

convert_template_arguments (continue)

 

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   }

 

如果参数是依赖类型(实参是其一个实例),或者实参是一个依赖值,不要尝试折叠这个实参。函数 uses_template_parms 可以告诉我们实参 t 是否依赖模板参数。

 

4795   int

4796   uses_template_parms (tree t)                                                                           in pt.c

4797   {

4798     bool dependent_p;

4799     int saved_processing_template_decl;

4800  

4801     saved_processing_template_decl = processing_template_decl;

4802     if (!saved_processing_template_decl)

4803       processing_template_decl = 1;

4804     if (TYPE_P (t))

4805       dependent_p = dependent_type_p (t);

4806     else if (TREE_CODE (t) == TREE_VEC)

4807       dependent_p = any_dependent_template_arguments_p (t);

4808     else if (TREE_CODE (t) == TREE_LIST)

4809       dependent_p = (uses_template_parms (TREE_VALUE (t))

4810                    || uses_template_parms (TREE_CHAIN (t)));

4811     else if (TREE_CODE (t) == TYPE_DECL)

4812       dependent_p = dependent_type_p (TREE_TYPE (t));

4813     else if (DECL_P (t)

4814           || EXPR_P (t)

4815           || TREE_CODE (t) == TEMPLATE_PARM_INDEX

4816           || TREE_CODE (t) == OVERLOAD

4817           || TREE_CODE (t) == BASELINK

4818           || TREE_CODE (t) == IDENTIFIER_NODE

4819           || TREE_CODE_CLASS (TREE_CODE (t)) == 'c')

4820       dependent_p = ( type_dependent_expression_p (t)

4821                    || value_dependent_expression_p (t));

4822     else if (t == error_mark_node)

4823       dependent_p = false;

4824     else

4825       abort ();

4826     processing_template_decl = saved_processing_template_decl;

4827  

4828     return dependent_p;

4829   }

 

在我们的例子中, template-id ThreadingModel< SmallObject<ThreadingModel, chunkSize, maxSmallObjectSize> > ”中“ SmallObject<ThreadingModel, chunkSize, maxSmallObjectSize> ”部分的实参“ ThreadingModel ”就是一个依赖于模板参数的例子。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值