Studying note of GCC-3.4.6 source (91)

5.12.3.1.2.        Process template parameter

Now we return from cp_parser_parameter_declaration, then cp_parser_template_parameter back to cp_parser_template_parameter_list, in which, variable parameter holds the tree node illustrated by above figure.

 

2161 tree

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

2163 {

2164   tree parm;

2165   tree decl = 0;

2166   tree defval;

2167   int is_type, idx;

2168

2169   parm = next;

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

2171   defval = TREE_PURPOSE (parm);

2172   parm = TREE_VALUE (parm);

2173   is_type = TREE_PURPOSE (parm) == class_type_node;

2174

2175   if (list)

2176   {

2177     tree p = TREE_VALUE (tree_last (list));

2178

2179     if (TREE_CODE (p) == TYPE_DECL || TREE_CODE (p) == TEMPLATE_DECL)

2180       idx = TEMPLATE_TYPE_IDX (TREE_TYPE (p));

2181     else

2182       idx = TEMPLATE_PARM_IDX (DECL_INITIAL (p));

2183     ++idx;

2184   }

2185   else

2186     idx = 0;

 

In above function, parameter list is the list of already processed template parameter. In this chain to quickly find out who is who, every parameter is indexed and the sequential number is saved within the node too. So it first needs to find out the last used number then the first unused number.

As for type template parameter, the type slot of tree_common part (accessed by TREE_TYPE); and initial slot of tree_decl (accessed by DECL_INITIAL, which is unused for common parm-decl) are of type template_parm_index which has following definition.

 

241  typedef struct template_parm_index_s GTY(())                                             in cp-tree.h

242  {

243    struct tree_common common;

244    HOST_WIDE_INT index;

245    HOST_WIDE_INT level;

246    HOST_WIDE_INT orig_level;

247    tree decl;

248  } template_parm_index;

 

And a series of macros have been defined for accessing related fields. Some of them are defined as below.

 

3443 #define TEMPLATE_PARM_INDEX_CAST(NODE) /                                  in cp-tree.h

3444        ((template_parm_index*)TEMPLATE_PARM_INDEX_CHECK (NODE))

3445 #define TEMPLATE_PARM_IDX(NODE) (TEMPLATE_PARM_INDEX_CAST (NODE)->index)

3446 #define TEMPLATE_PARM_LEVEL(NODE) (TEMPLATE_PARM_INDEX_CAST (NODE)->level)

3447 #define TEMPLATE_PARM_DESCENDANTS(NODE) (TREE_CHAIN (NODE))

3448 #define TEMPLATE_PARM_ORIG_LEVEL(NODE) (TEMPLATE_PARM_INDEX_CAST (NODE)->orig_level)

3449 #define TEMPLATE_PARM_DECL(NODE) (TEMPLATE_PARM_INDEX_CAST (NODE)->decl)

 

The TEMPLATE_PARM_IDX gives the index (from 0) of the parameter, while the TEMPLATE_PARM_LEVEL gives the level (from 1) of the parameter. Here's an example:

 

   template <class T> // Index 0, Level 1, Orig Level 1.

   struct S {

      template <class U, // Index 0, Level 2, Orig Level 2.

               class V> // Index 1, Level 2, Orig Level 2.

      void f();

   }; 

 

TEMPLATE_PARM_DESCENDANTS will be a chain of template_parm_index descended from above one. The first descendant will have the same IDX, but its LEVEL will be 1 less. The descendants are chained together by TREE_CHAIN. TEMPLATE_PARM_DECL is the parameter declaration, either TYPE_DECL or CONST_DECL. TEMPLATE_PARM_ORIG_LEVEL is the level of the most distant parent, i.e., the level that the parameter originally had when it was declared. For example, if we instantiate S<int>, we will have:

 

   struct S<int>    // N/A {

     template <class U, // Index 0, Level 1, Orig Level 2

              class V> // Index 1, Level 1, Orig Level 2

     void f();

   };

 

The LEVEL is the level of the parameter when we are worrying about the types of things; the ORIG_LEVEL is the level when we are worrying about instantiating things.

 

process_template_parm (continue)

 

2188   if (!is_type)

2189   {

        

2212   }

2213   else

2214   {

2215     tree t;

2216     parm = TREE_VALUE (parm);

2217      

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

2219     {

          

2226     }

2227     else

2228     {

2229       t = make_aggr_type (TEMPLATE_TYPE_PARM);

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

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

2232     }

2233        

2234     TYPE_NAME (t) = decl;

2235     TYPE_STUB_DECL (t) = decl;

2236     parm = decl;

2237     TEMPLATE_TYPE_PARM_INDEX (t)

2238         = build_template_parm_index (idx, processing_template_decl,

2239                                  processing_template_decl,

2240                                  decl, TREE_TYPE (parm));

2241   }

2242   DECL_ARTIFICIAL (decl) = 1;

2243   SET_DECL_TEMPLATE_PARM_P (decl);

2244   pushdecl (decl);

2245   parm = build_tree_list (defval, parm);

2246   return chainon (list, parm);

2247 }

 

Now our parameter “Host” is not a template declaration itself, a simple class type will be created for this parameter, it is regarded as a TYPE_DECL.

 

2104 static tree

2105 build_template_parm_index (int index,                                                               in pt.c

2106                         int level,

2107                        int orig_level,

2108                         tree decl,

2109                         tree type)

2110 {

2111   tree t = make_node (TEMPLATE_PARM_INDEX);

2112   TEMPLATE_PARM_IDX (t) = index;

2113   TEMPLATE_PARM_LEVEL (t) = level;

2114   TEMPLATE_PARM_ORIG_LEVEL (t) = orig_level;

2115   TEMPLATE_PARM_DECL (t) = decl;

2116   TREE_TYPE (t) = type;

2117   TREE_CONSTANT (t) = TREE_CONSTANT (decl);

2118   TREE_READONLY (t) = TREE_READONLY (decl);

2119

2120   return t;

2121 }

 

TEMPLATE_PARM_INDEX is a special tree node that of type template_parm_index. And it will never be created by user, but generated by front-end (DECL_ARTIFICIAL indicates this).

The template parameter is effective in scope of sk_template_parms. It should be added into the scope.

 

556  tree

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

558  {

559    tree t;

560    tree name;

561    int need_new_binding;

562 

563    timevar_push (TV_NAME_LOOKUP);

564 

565    need_new_binding = 1;

566 

567    if (DECL_TEMPLATE_PARM_P (x))

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

569         when declared within a class or namespace.  */

570      ;

     

604    name = DECL_NAME (x);

605    if (name)

606    {

607      int different_binding_level = 0;

        

615      /* In case this decl was explicitly namespace-qualified, look it

616        up in its namespace context.  */

617      if (DECL_NAMESPACE_SCOPE_P (x) && namespace_bindings_p ())

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

619      else

620        t = lookup_name_current_level (name);

 

Now cuurent scope is sk_template_parms, condition at line 617 is not satisfied so it tries to check if this identifier has been declared or not only at current binding level. Here we get NULL as result from lookup_name_current_level.

 

4019   static tree

4020   lookup_name_current_level (tree name)                                             in name-lookup.c

4021   {

4022     struct cp_binding_level *b;

4023     tree t = NULL_TREE;

4024  

4025     timevar_push (TV_NAME_LOOKUP);

4026     b = innermost_nonclass_level ();

4027  

4028     if (b->kind == sk_namespace)

4029     {

4030       t = IDENTIFIER_NAMESPACE_VALUE (name);

4031  

4032       /* extern "C" function() */

4033       if (t != NULL_TREE && TREE_CODE (t) == TREE_LIST)

4034         t = TREE_VALUE (t);

4035     }

4036     else if (IDENTIFIER_BINDING (name)

4037           && LOCAL_BINDING_P (IDENTIFIER_BINDING (name)))

4038     {

4039       while (1)

4040       {

4041         if (IDENTIFIER_BINDING (name)->scope == b)

4042           POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, IDENTIFIER_VALUE (name));

4043  

4044         if (b->kind == sk_cleanup)

4045           b = b->level_chain;

4046         else

4047           break;

4048       }

4049     }

4050  

4051     POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, t);

4052   }

 

Then this new declaration is installed within the scope by set_identifier_type_value at line 800. And at line 830, namespace_binding_p returns false, as the innermost non-class scope from current binding level is sk_template_parms.

 

pushdecl (continue)

 

772      /* If declaring a type as a typedef, copy the type (unless we're

773        at line 0), and install this TYPE_DECL as the new type's typedef

774        name. See the extensive comment in ../c-decl.c (pushdecl).  */

775      if (TREE_CODE (x) == TYPE_DECL)

776      {

777        tree type = TREE_TYPE (x);

          

797        if (type != error_mark_node

798          && TYPE_NAME (type)

799          && TYPE_IDENTIFIER (type))

800          set_identifier_type_value (DECL_NAME (x), x);

801      }

       

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

829        Install the new declaration and return it.  */

830      if (namespace_bindings_p ())

831      {

          

872      }

873      else

874      {

875        /* Here to install a non-global value.  */

876        tree oldlocal = IDENTIFIER_VALUE (name);

877        tree oldglobal = IDENTIFIER_NAMESPACE_VALUE (name);

878 

879        if (need_new_binding)

880        {

881          push_local_binding (name, x, 0);

882          /* Because push_local_binding will hook X on to the

883            current_binding_level's name list, we don't want to

884            do that again below.  */

885          need_new_binding = 0;

886        }

887 

888        /* If this is a TYPE_DECL, push it into the type value slot.  */

889        if (TREE_CODE (x) == TYPE_DECL)

890          set_identifier_type_value (name, x);

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}

 

For identifier, IDENTIFIER_VALUE field records the non-namespace binding scopes have the name defined, while IDNETIFIER_NAMESPACE_VALUE records the namespaces have the name defined. As “Host” is the new identifier, above, oldlocal and oldglobal are both NULL.

 

1052 void

1053 push_local_binding (tree id, tree decl, int flags)                                           in name-lookup.c

1054 {

1055   struct cp_binding_level *b;

1056

1057   /* Skip over any local classes. This makes sense if we call

1058     push_local_binding with a friend decl of a local class.  */

1059   b = innermost_nonclass_level ();

1060

1061   if (lookup_name_current_level (id))

1062   {

1063     /* Supplement the existing binding.  */

1064     if (!supplement_binding (IDENTIFIER_BINDING (id), decl))

1065       /* It didn't work. Something else must be bound at this

1066         level. Do not add DECL to the list of things to pop

1067         later.  */

1068       return;

1069   }

1070   else

1071     /* Create a new binding.  */

1072     push_binding (id, decl, b);

1073

1074   if (TREE_CODE (decl) == OVERLOAD || (flags & PUSH_USING))

1075     /* We must put the OVERLOAD into a TREE_LIST since the

1076       TREE_CHAIN of an OVERLOAD is already used. Similarly for

1077       decls that got here through a using-declaration.  */

1078     decl = build_tree_list (NULL_TREE, decl);

1079

1080   /* And put DECL on the list of things declared by the current

1081     binding level.  */

1082   add_decl_to_level (decl, b);

1083 }

 

No doubt, before insertion, it needs check if the name is new in the scope. Obviously, lookup_name_current_level returns NULL for “Host”. And at last, add_decl_to_level at line 1082 records the name of declaration into the binding scope. Next returns back pushdecl, at line 890, set_identifier_type_value the type of this identifier as the TYPE_DECL.

In the end, after installing the template parameter Host within the special sk_template_parm scope, we get the rough layout as following figure.

Studying note of GCC-3.4.6 source (91)_第1张图片

Studying note of GCC-3.4.6 source (91)_第2张图片

Figure 49: brief layout after pushing “Host”

Notice that current_template_parms records the nested level of template parameters. For a template declaration, its template parameter list contains parameter in form of template < template-parameter-list > class identifier [opt], current_template_parms can help to tell at which level should the parameter be bound.

 

2254 tree

2255 end_template_parm_list (tree parms)                                                                  in pt.c

2256 {

2257   int nparms;

2258   tree parm, next;

2259   tree saved_parmlist = make_tree_vec (list_length (parms));

2260

2261   current_template_parms

2262     = tree_cons (size_int (processing_template_decl),

2263                saved_parmlist, current_template_parms);

2264

2265   for (parm = parms, nparms = 0; parm; parm = next, nparms++)

2266   {

2267     next = TREE_CHAIN (parm);

2268     TREE_VEC_ELT (saved_parmlist, nparms) = parm;

2269     TREE_CHAIN (parm) = NULL_TREE;

2270   }

2271

2272   --processing_template_parmlist;

2273

2274   return saved_parmlist;

2275 }

 

748  #define current_template_parms scope_chain->template_parms                in cp-tree.h

 

Before moving ahead, considering following example:

template <typename A> class BoxA {

public:

   template<typename B, typename C> class BoxB {};

};

 

When processing class BoxB, notice that it is contained within a template class BoxA. Obvious, BoxB not only depends on type parameter B, but also on that type parameter A of BoxA; it is important that records type parameter A as part of template parameter during handling BoxB.

 

 

 

Figure 50: layout of nested template parameters

In current version, when handling declaration of BoxB, processing_template_decl will be 2 (assuming BoxA is within global scope), then before invoking end_template_parm_list to finish the processing of parameter of BoxB, current_template_parms holds the node with purpose of 1 which is the parameter of BoxA. After executing the function, we can have the layout of paramters for BoxB as above figure. See that the list holds parameters of different level, while value slot of each node holds parameters of the same level. At this point, the intermediate tree looks like:

Studying note of GCC-3.4.6 source (91)_第3张图片

Figure 51: Rough intermediate tree after handling template parameter

你可能感兴趣的:(Studying note of GCC-3.4.6 source (91))