我是靠谱客的博主 鲜艳滑板,最近开发中收集的这篇文章主要介绍Studying note of GCC-3.4.6 source (125),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

5.12.4.2.3.        Process base class
5.12.4.2.3.1.  Parse base-clause

Tokens after “SmallObject” are “: public ThreadingModel<SmallObject<ThreadingModel, chunkSize, maxSmallObjectSize> >”, which indicates the base class “SmallObject” derives from. Review the rule of class-head again in below.

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]

If nested-name-specifier is found, below variable nested_name_specifier will point to the tree object of it. And no doubt, it constructs a context that the base class should be visible within. Then at line 12330 below, if nested_name_specifier is not null, it should be make as current binding scope by 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 }

 

In fact, the part leading by “:” is called base-clause according to the grammar, it obeys following rules:

base-clause:

   : base-specifier-list 

base-specifier-list:

   base-specifier

   base-specifier-list , base-specifier

Obviously, if base-specifier-list contains more than one base-specifier, it corresponds to multiple-derivation. And these bases will be chained after variable bases in below function.

 

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 }

 

The part base-specifier describes from which to derive and by how. So its rules are obvious.

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 }

 

Above, cp_parser_nested_name_specifier_opt will set scope field of parser with present nested-name-specifier if any, which in turn will affect the rearching result of class-name look-up. At line 13051, cp_parser_optional_template_keyword checks if keyword “template” is present, if present and the nested-name-specifier indicates a class-scope, it is an explicit hint of name of template. For our case, template_p is false. The detail of class-name look-up is given before.

In brief decription, class “ThreadingModel” has been declared, in cp_parser_template_name at line 8212, cp_parser_lookup_name returns the corresponding TEMPLATE_DECL. The template argument “SmallObject<ThreadingModel, chunkSize, maxSmallObjectSize>” is a template-id again. Thus this time goes through 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 , again in cp_parser_template_name at the same line 8212, TEMPLATE_DECL of “SmallObject” is found (as the class tag has been handled), then next in cp_parser_template_id at line 7899, cp_parser_enclosed_template_argument_list is recursed.

5.12.4.2.3.1.1.          The inner template-id

And this time “ThreadingModel” is a type-id parsed by call-stack: cp_parser_type_id , cp_parser_type_specifier_seq , cp_parser_type_specifier , cp_parser_simple_type_specifier , cp_parser_type_name , in cp_parser_class_name at line 11795, again cp_parser_lookup_name returns the TEMPLATE_DECL associated, and in cp_parser_maybe_treat_template_as_class at line 11812, corresponding TYPE_DECL is retrieved from result field of the TEMPLATE_DECL. Then at line 10947 in cp_parser_type_id , groktypename returns the corresponding node of TEMPLATE_TEMPLATE_PARM from type field of the TYPE_DECL.

Next both “chunkSize” and “maxSmallObjectSize” are id-expression degraded from assignment-expression. Both IDENTIFIER_NODEs are returned. Then at line 7994 in cp_parser_template_id , as template is TEMPLATE_DECL, the template-id needs be created by finish_template_type as below.

 

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

 

Here arguments is the list of template-argument in form of tree_vec as below.

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   }

 

Also argument name refers to the TEMPLATE_DECL of “SmallObject” shown in below. We expect to see this tree after class “SmallObject” has its class tag processed, and notice that the last parameter “std::size_t maxSmallObjectSize” is left out to make the figure not to be too large, as we can see parameter almost the same “std::size_t chunkSize”.

(Click here for open )

Figure 110 : SmallObject after class tag handled

And for this time invocation, arguments in_decl , context are NULL, and entering_scope is 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;

 

Above template is updated at line 4187 as the TEMPLATE_DECL of “SmallObject” and dl is updated to corresponding IDENTIFIER_NODE, and context is NULL. And also template_type below is set to the node of TEMPLATE_TEMPLATE_PARM; then most_general_template at line 4271 returns the most-general declaration for the template (for our case, the template is the most general form). Traversing the arguments of the template in above figure, it gets parm_depth of 1, and arg_depth of 1 (arglist is the arguments shown in figure above).

Indicated their names, arg_depth corresponds to the depth of arguments of the template-id, while parm_depth is the depth of parameters of the template declaration. Case for both values unmatched is shown by the example:

template <class T> struct S1 {

    template <class U> struct S2 {};

};

In the definition of S2, the argument-list is “U”, but the full definition (if defining outside S1) is: template <class T> template <U> struct S1<T>::S2

It is what the parser expects! It must fill in the missing argument “T”. However, we are not in this trouble, we can skip it and go ahead.

 

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

 

After adding the extra arguments appropriately, arg_depth should equate to parm_depth , and case of parm_depth larger than 1 means handling member class template. It is not our fate here. At line 4347, INNERMOST_TEMPLATE_PARMS just returns the TREE_VEC node in above figure SmallObject after processing class tag , and INNERMOST_TEMPLATE_ARGS returns the arglist in whole.

 

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     }

 

Above at line 3818, NUM_TMPL_ARGS returns the TREE_VEC_LENGTH of the vector. See that at this step, the length of arguments must be no larger than the length of parameters. For our declaration, the length of arguments is 3 and is the same as the length of parameters. Now nparms holds this length.

 

coerce_template_parms (continue)

 

3838     new_inner_args = make_tree_vec (nparms);

3839     new_args = add_outermost_template_args (args, new_inner_args);

 

The case of number parameters larger than number of arguments, involves using default arguments. These default arguments must be added in by 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    }

 

For cases no using default arguments add_outermost_template_args does nothing but returns new_inner_args to new_args . Now parms is the TREE_VEC node in above figure SmallObject after processing class tag ; so for first element, parm points to below node.

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   }

 

In this invocation, argument parm is the TEMPLATE_DECL of “ThreadingModel”, arg also refers to this node. Above as nargs equates naprms , arg is fetched from 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;

 

Obviously, at this point, we have requires_tmpl_type (1), requires_type (1), is_tmpl_type (1), is_type (1). Among these variables, we can see that requires_tmpl_type is the subset of requires_type , and so is is_tmpl_type and is_type . Any inconsistency should be an error!

 

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.    The template-template argument

As parm and arg refer to the same TEMPALTE_DECL, then parmparm and argparm both point to TREE_VEC in below figure comes from the TEMPLATE_DECL of “ThreadingModel”.

(Click here for open )

 

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   }

 

The exactly matching types of parm_parms and arg_parms make the function returns 1. This function, besides validates template template argument and template template parameter, will fills up default argument.

Then at line 3745, in coerce_template_arguments , val is updated to the node of TEMPLATE_TEMPLATE_PARM in above figure. And this node in turn is placed into the first element of new_inner_args .

5.12.4.2.3.1.1.2.    The non-type argument

For the second argument, the argument arg of coerce_template_arguments is the IDENTIFIER_NODE of “chunkSize”, and parm is the node referred by the value field in red in below figure.

(Click here for open )

 

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   }

 

If the parameter is the dependent type (argument is an instance of it), or the argument is the dependent value, don’t attempt to fold the argument. Routine uses_template_parms can tell us if argument t depends upon template parameter.

 

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   }

 

In our example, in template-id “ThreadingModel< SmallObject<ThreadingModel, chunkSize, maxSmallObjectSize> >”, argument “ThreadingModel” in the part “SmallObject<ThreadingModel, chunkSize, maxSmallObjectSize>” is the one depends on template parameter.

最后

以上就是鲜艳滑板为你收集整理的Studying note of GCC-3.4.6 source (125)的全部内容,希望文章能够帮你解决Studying note of GCC-3.4.6 source (125)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(48)

评论列表共有 0 条评论

立即
投稿
返回
顶部