在解析了这个非类型模板参数之后,下一步,需要处理这个参数来完成相关的子树并插入中间树。
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 }
对于我们的例子:“ size_t chunkSize = 4096 ”,相关的子树被 process_template_parm 的参数 next 指向,在上面的 2172 行, parm 指向“ size_t chunSize ”部分。因此在调用 grokdeclarator 时,参数 declarator 指向节点“ chunkSize ”,而参数 declspecs 指向节点“ 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;
对于为 IDENTIFIER_NODE 的声明符,仅字面名被提取,并且这个名字被用于错误信息中以给出清晰的描述。那么对于 declspecs ,它是仅有一个 IDENTIFIER_NODE 的 tree_list ,它为上面的 id 所引用。然后在 6951 行, lookup_name 查找这个非限定名,并返回对应的 TYPE_DECL 节点。注意对于这个案例,解析器能够识别出它是应该 typedef 。因此在 6957 行的变量 type 指向 long_unsigned_type_node (假定 size_t 被 typedef 为 unsigned long ),而 typedef_decl 指向对应的 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 }
与类型参数相同,需要构建 TEMPLATE_PARM_INDEX 节点来代表这个参数。注意到模板参数 chunkSize 只能是常量。一个 CONST_DECL 节点被解析器自动创建来反映这一事实。从这里所构建的节点,可以很容易地辨别,这是一个模板声明中的参数声明的常量声明。
( 点此打开 )
图 107 :构建的非类型模板参数
然后这个名字必须被加入当前作用域,使得名字查找过程可以更有效地找到正确的声明。函数 pushdecl 执行与前面模板模板参数相同的代码,在这一点之后的参数列表看起来如下。
( 点此打开 )
图 108 :加入非类型参数
看到“ size_t ”的 IDENTIFIER_NODE 的 bindings 域现在指向 CONST_DECL 节点,它表示这个布局绑定的值。名字查找过程将返回这个绑定,作为在该作用域中查找的结果。
然后接下来的参数以同样的方式、过程来解析。为了尽量保持简洁,我们跳过这个过程,而中间树的布局可以相应地,很容易地画出来。当完成模板参数的解析时, end_template_parm_list 依照下图给参数打包(注意参数“ size_t maxSmallObjectSize ”部分没有画出)。
( 点此打开 )
图 109 : end_template_parm_list 的结果