After parsing this non-type template parameter, no doubt, next it needs process this parameter to finish the revelant sub-tree and insert it in the intermediate tree.
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;
2187
2188 if (!is_type)
2189 {
2190 my_friendly_assert (TREE_CODE (TREE_PURPOSE (parm)) == TREE_LIST, 260);
2191 /* is a const-param */
2192 parm = grokdeclarator (TREE_VALUE (parm), TREE_PURPOSE (parm),
2193 PARM, 0, NULL);
2194 SET_DECL_TEMPLATE_PARM_P (parm);
2195
2196 /* [temp.param]
2197
2198 The top-level cv-qualifiers on the template-parameter are
2199 ignored when determining its type. */
2200 TREE_TYPE (parm) = TYPE_MAIN_VARIANT (TREE_TYPE (parm));
2201
2202 /* A template parameter is not modifiable. */
2203 TREE_READONLY (parm) = TREE_CONSTANT (parm) = 1;
2204 if (invalid_nontype_parm_type_p (TREE_TYPE (parm), 1))
2205 TREE_TYPE (parm) = void_type_node;
2206 decl = build_decl (CONST_DECL, DECL_NAME (parm), TREE_TYPE (parm));
2207 TREE_CONSTANT (decl) = TREE_READONLY (decl) = 1;
2208 DECL_INITIAL (parm) = DECL_INITIAL (decl)
2209 = build_template_parm_index (idx, processing_template_decl,
2210 processing_template_decl,
2211 decl, TREE_TYPE (parm));
2212 }
2213 else
2214 {
…
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 }
For our example: “size_t chunkSize = 4096”, the relevant sub-tree is refered by argument next of process_template_parm , then at line 2172 above, parm points to the part of “size_t chunSize”. So at invocation of grokdeclarator , argument declarator points to tree nodes of “chunkSize”, then argument declspecs points to tree nodes “size_t”.
6462 tree
6463 grokdeclarator (tree declarator, in decl.c
6464 tree declspecs,
6465 enum decl_context decl_context,
6466 int initialized,
6467 tree* attrlist)
6468 {
6469 RID_BIT_TYPE specbits;
6470 int nclasses = 0;
6471 tree spec;
6472 tree type = NULL_TREE;
6473 int longlong = 0;
6474 int type_quals;
6475 int virtualp, explicitp, friendp, inlinep, staticp;
6476 int explicit_int = 0;
6477 int explicit_char = 0;
6478 int defaulted_int = 0;
6479 int extern_langp = 0;
6480 tree dependant_name = NULL_TREE;
6481
6482 tree typedef_decl = NULL_TREE;
6483 const char *name;
6484 tree typedef_type = NULL_TREE;
6485 int funcdef_flag = 0;
6486 enum tree_code innermost_code = ERROR_MARK;
6487 int bitfield = 0;
6488 #if 0
6489 /* See the code below that used this. */
6490 tree decl_attr = NULL_TREE;
6491 #endif
6492
6493 /* Keep track of what sort of function is being processed
6494 so that we can warn about default return values, or explicit
6495 return values which do not match prescribed defaults. */
6496 special_function_kind sfk = sfk_none;
6497
6498 tree dname = NULL_TREE;
6499 tree ctype = current_class_type ;
6500 tree ctor_return_type = NULL_TREE;
6501 enum overload_flags flags = NO_SPECIAL;
6502 tree quals = NULL_TREE;
6503 tree raises = NULL_TREE;
6504 int template_count = 0;
6505 tree in_namespace = NULL_TREE;
6506 tree returned_attrs = NULL_TREE;
6507 tree scope = NULL_TREE;
6508 tree parms = NULL_TREE;
6509
6510 RIDBIT_RESET_ALL (specbits);
6511 if (decl_context == FUNCDEF)
6512 funcdef_flag = 1, decl_context = NORMAL;
6513 else if (decl_context == MEMFUNCDEF)
6514 funcdef_flag = -1, decl_context = FIELD;
6515 else if (decl_context == BITFIELD)
6516 bitfield = 1, decl_context = FIELD;
6517
6518 /* Look inside a declarator for the name being declared
6519 and get it as a string, for an error message. */
6520 {
6521 tree *next = &declarator;
6522 tree decl;
6523 name = NULL;
6524
6525 while (next && *next)
6526 {
6527 decl = *next;
6528 switch (TREE_CODE (decl))
6529 {
…
6629 case IDENTIFIER_NODE:
6630 if (TREE_CODE (decl) == IDENTIFIER_NODE)
6631 dname = decl;
6632
6633 next = 0;
6634
6635 if (C_IS_RESERVED_WORD (dname))
6636 {
6637 error ("declarator-id missing; using reserved word `%D'",
6638 dname);
6639 name = IDENTIFIER_POINTER (dname);
6640 }
6641 else if (!IDENTIFIER_TYPENAME_P (dname))
6642 name = IDENTIFIER_POINTER (dname);
6643 else
6644 {
6645 my_friendly_assert (flags == NO_SPECIAL, 154);
6646 flags = TYPENAME_FLAG;
6647 ctor_return_type = TREE_TYPE (dname);
6648 sfk = sfk_conversion;
6649 if (is_typename_at_global_scope (dname))
6650 name = IDENTIFIER_POINTER (dname);
6651 else
6652 name = "<invalid operator>";
6653 }
6654 break ;
…
6784 }
6785 }
6786 }
6787
6788 /* A function definition's declarator must have the form of
6789 a function declarator. */
6790
6791 if (funcdef_flag && innermost_code != CALL_EXPR)
6792 return 0;
…
6828 /* Look through the decl specs and record which ones appear.
6829 Some typespecs are defined as built-in typenames.
6830 Others, the ones that are modifiers of other types,
6831 are represented by bits in SPECBITS: set the bits for
6832 the modifiers that appear. Storage class keywords are also in SPECBITS.
6833
6834 If there is a typedef name or a type, store the type in TYPE.
6835 This includes builtin typedefs such as `int'.
6836
6837 Set EXPLICIT_INT if the type is `int' or `char' and did not
6838 come from a user typedef.
6839
6840 Set LONGLONG if `long' is mentioned twice.
6841
6842 For C++, constructors and destructors have their own fast treatment. */
6843
6844 for (spec = declspecs; spec; spec = TREE_CHAIN (spec))
6845 {
6846 int i;
6847 tree id;
6848
6849 /* Certain parse errors slip through. For example,
6850 `int class;' is not caught by the parser. Try
6851 weakly to recover here. */
6852 if (TREE_CODE (spec) != TREE_LIST)
6853 return 0;
6854
6855 id = TREE_VALUE (spec);
6856
6857 /* If the entire declaration is itself tagged as deprecated then
6858 suppress reports of deprecated items. */
6859 if (!adding_implicit_members && id && TREE_DEPRECATED (id))
6860 {
6861 if (deprecated_state != DEPRECATED_SUPPRESS)
6862 warn_deprecated_use (id);
6863 }
6864
6865 if (TREE_CODE (id) == IDENTIFIER_NODE)
6866 {
6867 if (id == ridpointers [(int) RID_INT]
6868 || id == ridpointers [(int) RID_CHAR]
6869 || id == ridpointers [(int) RID_BOOL]
6870 || id == ridpointers [(int) RID_WCHAR])
6871 {
…
6888 }
6889 /* C++ aggregate types. */
6890 if (IDENTIFIER_HAS_TYPE_VALUE (id))
6890 {
…
6896 }
…
6947 if (type)
6948 error ("two or more data types in declaration of `%s'", name);
6949 else if (TREE_CODE (id) == IDENTIFIER_NODE)
6950 {
6951 tree t = lookup_name (id, 1);
6952 if (!t || TREE_CODE (t) != TYPE_DECL)
6953 error ("`%s' fails to be a typedef or built in type",
6954 IDENTIFIER_POINTER (id));
6955 else
6956 {
6957 type = TREE_TYPE (t);
6958 typedef_decl = t;
6959 }
6960 }
…
6965 found: ;
6966 }
6967
6968 #if 0
6969 /* See the code below that used this. */
6970 if (typedef_decl)
6971 decl_attr = DECL_ATTRIBUTES (typedef_decl);
6972 #endif
6973 typedef_type = type;
For declarator of IDENTIFIER_NODE only literal name is retrieved, and this name is used in error message to give out a clear description. Then for declspecs , it is a tree_list of only node of IDENTIFIER_NODE, which is refered by id above. Then lookup_name at line 6951 looks up this unqualified-name, and the corresponding TYPE_DECL node would be returned. Notice that for the case, the parser can recognize that it is a typedef. So variable type at line 6957 points to long_unsigned_type_node (assuming size_t is typedef as unsigned long), and typedef_decl points to the TYPE_DECL.
grokdeclarator (continue)
8163 {
8164 tree decl;
8165
8166 if (decl_context == PARM)
8167 {
8168 decl = cp_build_parm_decl (declarator, type);
8169
8170 bad_specifiers (decl, "parameter", virtualp, quals != NULL_TREE,
8171 inlinep, friendp, raises != NULL_TREE);
8172 }
…
8750 return decl;
8751 }
8752 }
Same as type-parameter, node of TEMPLATE_PARM_INDEX needs be created to stand for this parameter. Note that template parameter chunkSize can only be constant. A node of CONST_DECL is created automatically by parser to indicate the fact. From the nodes built here, it can easily tell out that, it is a constant declaration of parameter declaration of template declaration.
(Click here for open )
Figure 107 : non-type template parameter built
Then the name must be pushed within current binding scope and let later name-lookup procedure find out the correct declaration more efficiently. Routine pushdecl runs the same code as previous template template parameter, and the parameter list after this point looks like below.
(Click here for open )
Figure 108 : non-type template parameter pushed
See that bindings field of IDENTIFIER_NODE of “size_t” points to the CONST_DECL now, which indicates the local binding value. Name-lookup procedure will return this binding as result of searching within the scope.
Then the following parameter is parsed and processed exactly the same. To keep concise as possible, we just skip the procedure, and the intermediate tree layout can be drawn accordingly and easily. When finishing parsing the template parameters, end_template_parm_list packs the paramters according to following figure (note that the part of parameter of “size_t maxSmallObjectSize” is not present in figure).
(Click here for open )
Figure 109 : result of end_template_parm_list