5.12.5.2.2.2.1.3.1. 具现基类 – 实参替换
基类可能依赖于模板参数,就像这里我们的例子那样。因此要具现派生类,首先需要正确地具现其基类。在这里我们为了方便起见,在下面重新显示了“ SmallObject ”部分的中间树。“ SmallObject ”具有单个基类——“ ThreadingModel ”,其缺省类型是“ SingleThreaded ”,而且“ SmallObject ”声明在名字空间“ Loki ”中。
(点此打开 )
图 115 :“ SmallObject ” 部分的中间树
在 instantiate_class_template 中的 5320 行 , pattern 是图中上部的 RECORD_TYPE 节点 ; 而在 5400 行的 pinfo 为 pattern 的 binfo 域所指向。那么在 5425 行,名字空间“ Loki ”成为了当前的作用域。因此在 5439 行,调用 tsubst 的第一个实参是节点 BOUND_TEMPLATE_TEMPLATE_PARM , 而第二个实参 args 是下图中红色的 tree_vec 节点。
( 点此打开 )
图 116 : VAR_DECL 部分的中间树
6681 static tree
6682 tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) in pt.c
6683 {
6684 tree type, r;
6685
6686 if (t == NULL_TREE || t == error_mark_node
6687 || t == integer_type_node
6688 || t == void_type_node
6689 || t == char_type_node
6690 || t == unknown_type_node
6691 || TREE_CODE (t) == NAMESPACE_DECL)
6692 return t;
6693
6694 if (TREE_CODE (t) == IDENTIFIER_NODE)
6695 type = IDENTIFIER_TYPE_VALUE (t);
6696 else
6697 type = TREE_TYPE (t);
6698
6699 my_friendly_assert (type != unknown_type_node, 20030716);
6700
6701 if (type && TREE_CODE (t) != FUNCTION_DECL
6702 && TREE_CODE (t) != TYPENAME_TYPE
6703 && TREE_CODE (t) != TEMPLATE_DECL
6704 && TREE_CODE (t) != IDENTIFIER_NODE
6705 && TREE_CODE (t) != FUNCTION_TYPE
6706 && TREE_CODE (t) != METHOD_TYPE)
6707 type = tsubst (type, args, complain, in_decl);
6708 if (type == error_mark_node)
6709 return error_mark_node;
6710
6711 if (DECL_P (t))
6712 return tsubst_decl (t, args, type, complain);
6713
6714 switch (TREE_CODE (t))
6715 {
…
6776 case TEMPLATE_TYPE_PARM:
6777 case TEMPLATE_TEMPLATE_PARM:
6778 case BOUND_TEMPLATE_TEMPLATE_PARM:
6779 case TEMPLATE_PARM_INDEX:
6780 {
6781 int idx;
6782 int level;
6783 int levels;
6784
6785 r = NULL_TREE;
6786
6787 if (TREE_CODE (t) == TEMPLATE_TYPE_PARM
6788 || TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM
6789 || TREE_CODE (t) == BOUND_TEMPLATE_TEMPLATE_PARM)
6790 {
6791 idx = TEMPLATE_TYPE_IDX (t);
6792 level = TEMPLATE_TYPE_LEVEL (t);
6793 }
6794 else
6795 {
6796 idx = TEMPLATE_PARM_IDX (t);
6797 level = TEMPLATE_PARM_LEVEL (t);
6798 }
6799
6800 if (TREE_VEC_LENGTH (args) > 0)
6801 {
6802 tree arg = NULL_TREE;
6803
6804 levels = TMPL_ARGS_DEPTH (args);
6805 if (level <= levels)
6806 arg = TMPL_ARG (args, level, idx);
6807
6808 if (arg == error_mark_node)
6809 return error_mark_node;
6810 else if (arg != NULL_TREE)
6811 {
6812 if (TREE_CODE (t) == TEMPLATE_TYPE_PARM)
6813 {
6814 my_friendly_assert (TYPE_P (arg), 0);
6815 return cp_build_qualified_type_real
6816 (arg, cp_type_quals (arg) | cp_type_quals (t),
6817 complain | tf_ignore_bad_quals);
6818 }
6819 else if (TREE_CODE (t) == BOUND_TEMPLATE_TEMPLATE_PARM)
6820 {
6821 /* We are processing a type constructed from
6822 a template template parameter. */
6823 tree argvec = tsubst (TYPE_TI_ARGS (t),
6824 args, complain, in_decl);
6825 if (argvec == error_mark_node)
6826 return error_mark_node;
因为 t 指向节点 BOUND_TEMPLATE_TEMPALTE_PARM ,在 6791 行 idx 是 0 ,而 level 是 1 ;然后在 6806 行, arg 指向“ SingleThreaded ”对应的 TEMPLATE_DECL 节点。注意到在 6823 行,对于我们的例子, tsubst 的第一个实参“ TYPE_TI_ARGS (t) ”参考本节中第一个图中的包含 2 个元素的 tree_vec 节点【其定义为: (TI_ARGS (TYPE_TEMPLATE_INFO (NODE))) 】。
6681 static tree
6682 tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) in pt.c
6683 {
6684 tree type, r;
...
6694 if (TREE_CODE (t) == IDENTIFIER_NODE)
6695 type = IDENTIFIER_TYPE_VALUE (t);
6696 else
6697 type = TREE_TYPE (t);
…
6714 switch (TREE_CODE (t))
6715 {
…
6950 case TREE_VEC:
6951 if (type != NULL_TREE)
6952 {
…
6970 }
6971
6972 /* Otherwise, a vector of template arguments. */
6973 return tsubst_template_args (t, args, complain, in_decl);
…
7304 }
7305 }
这里实参 t 代表模板的参数,而 args 代表具现时的实参。对于模板,因为语义检查( semantic check )应该在具现点进行, tsubst_template_args 会验证实参是否与参数相符。现在 t 指向如下的红色节点。
5744 static tree
5745 tsubst_template_args (tree t, tree args, tsubst_flags_t complain, tree in_decl) in pt.c
5746 {
5747 int len = TREE_VEC_LENGTH (t);
5748 int need_new = 0, i;
5749 tree *elts = alloca (len * sizeof (tree));
5750
5751 for (i = 0; i < len; i++)
5752 {
5753 tree orig_arg = TREE_VEC_ELT (t, i);
5754 tree new_arg;
5756
5757 if (TREE_CODE (orig_arg) == TREE_VEC)
5758 new_arg = tsubst_template_args (orig_arg, args, complain, in_decl);
5759 else
5760 new_arg = tsubst_template_arg (orig_arg, args, complain, in_decl);
5761
5762 if (new_arg == error_mark_node)
5763 return error_mark_node;
5764
5765 elts[i] = new_arg;
5766 if (new_arg != orig_arg)
5767 need_new = 1;
5768 }
5769
5770 if (!need_new)
5771 return t;
5772
5773 t = make_tree_vec (len);
5774 for (i = 0; i < len; i++)
5775 TREE_VEC_ELT (t, i) = elts[i];
5776
5777 return t;
5778 }
看到在 t 中的第一个元素是一个 tree_vec ,它是外层模板的参数。这个 tree_vec (第一个元素)及作为内层模板参数的第二个元素, 都由 tsubst_template_arg 来处理。在这个函数在,对于所有的候选者, TYPE_P 返回 0 因为它们都不是代表类型的节点。看到在调用 tsubst_expr 时参数 t 及 args 与调用 tsubst_template_arg 时相同。
7822 static tree
7823 tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) in pt.c
7824 {
7825 tree stmt, tmp;
7826 tsubst_flags_t stmt_expr
7827 = complain & (tf_stmt_expr_cmpd | tf_stmt_expr_body);
7828
7829 complain ^= stmt_expr;
7830 if (t == NULL_TREE || t == error_mark_node)
7831 return t;
7832
7833 if (!STATEMENT_CODE_P (TREE_CODE (t)))
7834 return tsubst_copy_and_build (t, args, complain, in_decl,
7835 /*function_p=*/ false);
…
8156 }
这里所有的模板实参都不是语句( statement )因此都是调用 tsubst_copy_and_build 。
8179 tree
8180 tsubst_copy_and_build (tree t, in pt.c
8181 tree args,
8182 tsubst_flags_t complain,
8183 tree in_decl,
8184 bool function_p)
8185 {
8186 #define RECUR(NODE) /
8187 tsubst_copy_and_build (NODE, args, complain, in_decl, /*function_p=*/ false)
8188
8189 tree op1;
8190
8191 if (t == NULL_TREE || t == error_mark_node)
8192 return t;
8193
8194 switch (TREE_CODE (t))
8195 {
…
8693 default :
8694 return tsubst_copy (t, args, complain, in_decl);
8695 }
8696
8697 #undef RECUR
8698 }
对于外层模板参数,第一个是 TEMPLATE_TEMPALTE_PARM ,第二及第三都是 TEMPLATE_PARM_INDEX ;而内层模板的参数是 TEMPLATE_TYPE_PARM 。所有这些节点都由 tsubst_copy 来处理。
7449 static tree
7450 tsubst_copy (tree t, tree args, tsubst_flags_t complain, tree in_decl) in pt.c
7451 {
7452 enum tree_code code;
7453 tree r;
7454
7455 if (t == NULL_TREE || t == error_mark_node)
7456 return t;
7457
7458 code = TREE_CODE (t);
7469
7460 switch (code)
7461 {
…
7767 case RECORD_TYPE:
7768 case UNION_TYPE:
7769 case ENUMERAL_TYPE:
7770 case INTEGER_TYPE:
7771 case TEMPLATE_TYPE_PARM:
7772 case TEMPLATE_TEMPLATE_PARM:
7773 case BOUND_TEMPLATE_TEMPLATE_PARM:
7774 case TEMPLATE_PARM_INDEX:
7775 case POINTER_TYPE:
7776 case REFERENCE_TYPE:
7777 case OFFSET_TYPE:
7778 case FUNCTION_TYPE:
7779 case METHOD_TYPE:
7780 case ARRAY_TYPE:
7781 case TYPENAME_TYPE:
7782 case UNBOUND_CLASS_TEMPLATE:
7783 case TYPEOF_TYPE:
7784 case TYPE_DECL:
7785 return tsubst (t, args, complain, in_decl);
…
7816 }
7817 }
对于这些节点,再一次调用了 tsubst 。记得 t 指向模板参数,而 args 持有模板的实参。
6681 static tree
6682 tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) in pt.c
6683 {
6684 tree type, r;
6685
6686 if (t == NULL_TREE || t == error_mark_node
6687 || t == integer_type_node
6688 || t == void_type_node
6689 || t == char_type_node
6690 || t == unknown_type_node
6691 || TREE_CODE (t) == NAMESPACE_DECL)
6692 return t;
6693
6694 if (TREE_CODE (t) == IDENTIFIER_NODE)
6695 type = IDENTIFIER_TYPE_VALUE (t);
6696 else
6697 type = TREE_TYPE (t);
6698
6699 my_friendly_assert (type != unknown_type_node, 20030716);
6700
6701 if (type && TREE_CODE (t) != FUNCTION_DECL
6702 && TREE_CODE (t) != TYPENAME_TYPE
6703 && TREE_CODE (t) != TEMPLATE_DECL
6704 && TREE_CODE (t) != IDENTIFIER_NODE
6705 && TREE_CODE (t) != FUNCTION_TYPE
6706 && TREE_CODE (t) != METHOD_TYPE)
6707 type = tsubst (type, args, complain, in_decl);
6708 if (type == error_mark_node)
6709 return error_mark_node;
6710
6711 if (DECL_P (t))
6712 return tsubst_decl (t, args, type, complain);
6713
6714 switch (TREE_CODE (t))
6715 {
…
6776 case TEMPLATE_TYPE_PARM:
6777 case TEMPLATE_TEMPLATE_PARM:
6778 case BOUND_TEMPLATE_TEMPLATE_PARM:
6779 case TEMPLATE_PARM_INDEX:
6780 {
6781 int idx;
6782 int level;
6783 int levels;
6784
6785 r = NULL_TREE;
6786
6787 if (TREE_CODE (t) == TEMPLATE_TYPE_PARM
6788 || TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM
6789 || TREE_CODE (t) == BOUND_TEMPLATE_TEMPLATE_PARM)
6790 {
6791 idx = TEMPLATE_TYPE_IDX (t);
6792 level = TEMPLATE_TYPE_LEVEL (t);
6793 }
6794 else
6795 {
6796 idx = TEMPLATE_PARM_IDX (t);
6797 level = TEMPLATE_PARM_LEVEL (t);
6798 }
6799
6800 if (TREE_VEC_LENGTH (args) > 0)
6801 {
6802 tree arg = NULL_TREE;
6803
6804 levels = TMPL_ARGS_DEPTH (args);
6805 if (level <= levels)
6806 arg = TMPL_ARG (args, level, idx);
6807
6808 if (arg == error_mark_node)
6809 return error_mark_node;
6810 else if (arg != NULL_TREE)
6811 {
6812 if (TREE_CODE (t) == TEMPLATE_TYPE_PARM)
6813 {
…
6818 }
6819 else if (TREE_CODE (t) == BOUND_TEMPLATE_TEMPLATE_PARM)
6820 {
…
6843 }
6844 else
6845 /* TEMPLATE_TEMPLATE_PARM or TEMPLATE_PARM_INDEX. */
6846 return arg;
6847 }
6848 }
…
6907 }
…
7304 }
7305 }
节点 TEMPLATE_TEMPLATE_PRAM 有空的 type 域。而在 6791 行,根据相应的 TEMPLATE_PARM_INDEX 节点,把 idx 及 level 分别设置为 0 及 1 。在 6806 行 arg 指向“ SingleThreaded ”的 TEMPALTE_DECL 节点。当把这个节点返回给 tsubst_template_arg 时,在 5713 行的 uses_template_parms 对这个节点返回 0 ,因为这个节点不是依赖性的。而这个节点被继续返回。
外层模板的第二个参数是下图中的 TEMPLATE_PARM_INDEX 节点。而在 6806 行, arg 指向上一图中的 INTEGER_CST 整形常量 4096 ;并且它同样在 6846 行被返回。
( 点此打开 )
类似的还有外层模板的第三个参数,在前一节我们忽略了它。对于内层模板,其参数是下图中的 TEMPLATE_TYPE_PARM 节点。
在图中被相应的 TEMPLATE_PARM_INDEX 所记录的 level 是 2 ,同时 args 所显示的 level 是 1 ;下面是 tsubst 中为这个节点执行的代码。
6681 static tree
6682 tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) in pt.c
6683 {
6684 tree type, r;
…
6694 if (TREE_CODE (t) == IDENTIFIER_NODE)
6695 type = IDENTIFIER_TYPE_VALUE (t);
6696 else
6697 type = TREE_TYPE (t);
…
6714 switch (TREE_CODE (t))
6715 {
…
6776 case TEMPLATE_TYPE_PARM:
6777 case TEMPLATE_TEMPLATE_PARM:
6778 case BOUND_TEMPLATE_TEMPLATE_PARM:
6779 case TEMPLATE_PARM_INDEX:
6780 {
6781 int idx;
6782 int level;
6783 int levels;
6784
6785 r = NULL_TREE;
6786
6787 if (TREE_CODE (t) == TEMPLATE_TYPE_PARM
6788 || TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM
6789 || TREE_CODE (t) == BOUND_TEMPLATE_TEMPLATE_PARM)
6790 {
6791 idx = TEMPLATE_TYPE_IDX (t);
6792 level = TEMPLATE_TYPE_LEVEL (t);
6793 }
6794 else
6795 {
6796 idx = TEMPLATE_PARM_IDX (t);
6797 level = TEMPLATE_PARM_LEVEL (t);
6798 }
6799
6800 if (TREE_VEC_LENGTH (args) > 0)
6801 {
6802 tree arg = NULL_TREE;
6803
6804 levels = TMPL_ARGS_DEPTH (args);
6805 if (level <= levels)
6806 arg = TMPL_ARG (args, level, idx);
6807
6808 if (arg == error_mark_node)
6809 return error_mark_node;
6810 else if (arg != NULL_TREE)
6811 {
…
6847 }
6848 }
6849 else
6850 abort ();
6851
6852 if (level == 1)
6853 /* This can happen during the attempted tsubst'ing in
6854 unify. This means that we don't yet have any information
6855 about the template parameter in question. */
6856 return t;
6857
6858 /* If we get here, we must have been looking at a parm for a
6859 more deeply nested template. Make a new version of this
6860 template parameter, but with a lower level. */
6861 switch (TREE_CODE (t))
6862 {
6863 case TEMPLATE_TYPE_PARM:
6864 case TEMPLATE_TEMPLATE_PARM:
6865 case BOUND_TEMPLATE_TEMPLATE_PARM:
6866 if (cp_type_quals (t))
6867 {
…
6873 }
6874 else
6875 {
6876 r = copy_type (t);
6877 TEMPLATE_TYPE_PARM_INDEX (r)
6878 = reduce_template_parm_level (TEMPLATE_TYPE_PARM_INDEX (t),
6879 r, levels);
6880 TYPE_STUB_DECL (r) = TYPE_NAME (r) = TEMPLATE_TYPE_DECL (r);
6881 TYPE_MAIN_VARIANT (r) = r;
6882 TYPE_POINTER_TO (r) = NULL_TREE;
6883 TYPE_REFERENCE_TO (r) = NULL_TREE;
6884
6885 if (TREE_CODE (t) == BOUND_TEMPLATE_TEMPLATE_PARM)
6886 {
…
6894 }
6895 }
6896 break ;
6897
6898 case TEMPLATE_PARM_INDEX:
6899 r = reduce_template_parm_level (t, type, levels);
6900 break ;
6901
6902 default :
6903 abort ();
6904 }
6905
6906 return r;
6907 }
…
7304 }
7305 }
上面在 6878 行, TEMPLATE_TYPE_PARM_INDEX 提取在 TEMPLATE_TYPE_PARM 节点的 value 域中的节点,它是 TEMPLATE_PARM_INDEX 节点。
2128 static tree
2129 reduce_template_parm_level (tree index, tree type, int levels) in pt.c
2130 {
2131 if (TEMPLATE_PARM_DESCENDANTS (index) == NULL_TREE
2132 || (TEMPLATE_PARM_LEVEL (TEMPLATE_PARM_DESCENDANTS (index))
2133 != TEMPLATE_PARM_LEVEL (index) - levels))
2134 {
2135 tree orig_decl = TEMPLATE_PARM_DECL (index);
2136 tree decl, t;
2137
2138 decl = build_decl (TREE_CODE (orig_decl), DECL_NAME (orig_decl), type);
2139 TREE_CONSTANT (decl) = TREE_CONSTANT (orig_decl);
2140 TREE_READONLY (decl) = TREE_READONLY (orig_decl);
2141 DECL_ARTIFICIAL (decl) = 1;
2142 SET_DECL_TEMPLATE_PARM_P (decl);
2143
2144 t = build_template_parm_index (TEMPLATE_PARM_IDX (index),
2145 TEMPLATE_PARM_LEVEL (index) - levels,
2146 TEMPLATE_PARM_ORIG_LEVEL (index),
2147 decl, type);
2148 TEMPLATE_PARM_DESCENDANTS (index) = t;
2149
2150 /* Template template parameters need this. */
2151 DECL_TEMPLATE_PARMS (decl)
2152 = DECL_TEMPLATE_PARMS (TEMPLATE_PARM_DECL (index));
2153 }
2154
2155 return TEMPLATE_PARM_DESCENDANTS (index);
2156 }
上面,一个新的带有减少的 level 的 TEMPLATE_PARM_INDEX 被构建来代表内层模板参数的具现。并且这个节点作为原始 TEMPLATE_PARM_INDEX 节点的直接后代。
然后在 tsubst 的 6823 行,下图中的 BOUND_TEMPLATE_TEMPLATE_PARM 节点所包含的参数,嵌套的 tsubst 为之构建了 argvec 。
( 点此打开 )
继续在 tsubst 中处理 BOUND_TEMPLATE_TEMPLATE_PARM 节点,记得下面的 arg 指向下图中“ SingleThreaded ” 的 TEMPLATE_DECL 。因为现在我们正在具现外层的模板,首先具现内层模板是先决条件。这通过下面的 lookup_template_class 隐蔽地完成。
tsubst (continue)
6828 /* We can get a TEMPLATE_TEMPLATE_PARM here when
6829 we are resolving nested-types in the signature of
6830 a member function templates.
6831 Otherwise ARG is a TEMPLATE_DECL and is the real
6832 template to be instantiated. */
6833 if (TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM)
6834 arg = TYPE_NAME (arg);
6835
6836 r = lookup_template_class (arg,
6837 argvec, in_decl,
6838 DECL_CONTEXT (arg),
6839 /*entering_scope=*/ 0,
6840 complain);
6841 return cp_build_qualified_type_real
6842 (r, TYPE_QUALS (t), complain);
6843 }
6844 else
6845 /* TEMPLATE_TEMPLATE_PARM or TEMPLATE_PARM_INDEX. */
6846 return arg;
6847 }
6848 }
6849 else
6850 abort ();
那么在调用 lookup_template_class 时,实参 dl 是下图中红色的 TEMPLATE_DECL , arglist 是上面 tusbst 中的 argvec ,而 context 是作用域“ Loki ”。
( 点此打开 )
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 {
…
4162 }
4163 else if (TREE_CODE (d1) == TYPE_DECL && IS_AGGR_TYPE (TREE_TYPE (d1)))
4164 {
…
4177 }
4178 else if (TREE_CODE (d1) == ENUMERAL_TYPE
4179 || (TYPE_P (d1) && IS_AGGR_TYPE (d1)))
4180 {
…
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 }
…
4219 complain &= ~tf_user;
4220
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 {
…
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);
4351
4352 if (arglist == error_mark_node)
4353 /* We were unable to bind the arguments. */
4354 POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, error_mark_node);
上面的 parmlist 是被“ SingleThreaded ”的 TEMPLATE_DECL 中的 arguments 域所指向的 tree_list 链。因此下面的实参 parms 是被这个 tree_list 的 value 域所引用的 tree_vec ;这是在声明中的参数。接下来的 INNERMOST_TEMPLATE_ARGS 访问上面 argvec 的第二个元素——内层模板的实参。
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);
…
3838 new_inner_args = make_tree_vec (nparms);
3839 new_args = add_outermost_template_args (args, new_inner_args);
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 }
因为 parms 及 args 都是大小为 1 的 tree_vec , 3829 行的 add_outermost_template_args 不做任何事。接着在 3850 行, arg 指向新构建的 TEMPLATE_TYPE_PARM 节点。
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);
…
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;
…
3722 if (is_type)
3723 {
3724 if (requires_tmpl_type)
3725 {
…
3759 }
3760 else
3761 val = groktypename (arg);
3762 }
3763 else
3764 {
…
3790 }
3791
3792 return val;
3793 }
TEMPLATE_TYPE_PARM 节点被视为类型 , 所以 3676 行的 is_type 是 , 因为 TYPE_P 对 arg 返回 true 。接着在 3761 行,因为 arg 不是一个 tree_list , groktypename 仅是把 arg 返回来。注意到在 lookup_template_class 的 4347 行, arg 被替换入 arglist 。
lookup_template_class (continue)
4356 /* In the scope of a template class, explicit references to the
4357 template class refer to the type of the template, not any
4358 instantiation of it. For example, in:
4359
4360 template <class T> class C { void f(C<T>); }
4361
4362 the `C<T>' is just the same as `C'. Outside of the
4363 class, however, such a reference is an instantiation. */
4364 if (comp_template_args (TYPE_TI_ARGS (template_type),
4365 arglist))
4366 {
4367 found = template_type;
4368
4369 if (!entering_scope && PRIMARY_TEMPLATE_P (template))
4370 {
4371 tree ctx;
4372
4373 for (ctx = current_class_type ;
4374 ctx && TREE_CODE (ctx) != NAMESPACE_DECL;
4375 ctx = (TYPE_P (ctx)
4376 ? TYPE_CONTEXT (ctx)
4377 : DECL_CONTEXT (ctx)))
4378 if (TYPE_P (ctx) && same_type_p (ctx, template_type))
4379 goto found_ctx;
4380
4381 /* We're not in the scope of the class, so the
4382 TEMPLATE_TYPE is not the type we want after all. */
4383 found = NULL_TREE;
4384 found_ctx:;
4385 }
4386 }
4387 if (found)
4388 POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, found);
…
4431 context = tsubst (DECL_CONTEXT (template), arglist,
4432 complain, in_decl);
4433 if (!context)
4434 context = global_namespace ;
4435
4436 /* Create the type. */
4437 if (TREE_CODE (template_type) == ENUMERAL_TYPE)
4438 {
…
4450 }
4451 else
4452 {
4453 t = make_aggr_type (TREE_CODE (template_type));
4454 CLASSTYPE_DECLARED_CLASS (t)
4455 = CLASSTYPE_DECLARED_CLASS (template_type);
4456 SET_CLASSTYPE_IMPLICIT_INSTANTIATION (t);
4457 TYPE_FOR_JAVA (t) = TYPE_FOR_JAVA (template_type);
4458
4459 /* A local class. Make sure the decl gets registered properly. */
4460 if (context == current_function_decl )
4461 pushtag (DECL_NAME (template), t, 0);
4462 }
4463
4464 /* If we called start_enum or pushtag above, this information
4465 will already be set up. */
4466 if (!TYPE_NAME (t))
4467 {
4468 TYPE_CONTEXT (t) = FROB_CONTEXT (context);
4469
4470 type_decl = create_implicit_typedef (DECL_NAME (template), t);
4471 DECL_CONTEXT (type_decl) = TYPE_CONTEXT (t);
4472 TYPE_STUB_DECL (t) = type_decl;
4473 DECL_SOURCE_LOCATION (type_decl)
4474 = DECL_SOURCE_LOCATION (TYPE_STUB_DECL (template_type));
4475 }
4476 else
4477 type_decl = TYPE_NAME (t);
4478
4479 TREE_PRIVATE (type_decl)
4480 = TREE_PRIVATE (TYPE_STUB_DECL (template_type));
4481 TREE_PROTECTED (type_decl)
4482 = TREE_PROTECTED (TYPE_STUB_DECL (template_type));
4483
4484 /* Set up the template information. We have to figure out which
4485 template is the immediate parent if this is a full
4486 instantiation. */
4487 if (parm_depth == 1 || is_partial_instantiation
4488 || !PRIMARY_TEMPLATE_P (template))
4489 /* This case is easy; there are no member templates involved. */
4490 found = template;
4491 else
4492 {
…
4544 }
4545
4546 SET_TYPE_TEMPLATE_INFO (t, tree_cons (found, arglist, NULL_TREE));
4547 DECL_TEMPLATE_INSTANTIATIONS (template)
4548 = tree_cons (arglist, t,
4549 DECL_TEMPLATE_INSTANTIATIONS (template));
4550
4551 if (TREE_CODE (t) == ENUMERAL_TYPE
4552 && !is_partial_instantiation)
4553 /* Now that the type has been registered on the instantiations
4554 list, we set up the enumerators. Because the enumeration
4555 constants may involve the enumeration type itself, we make
4556 sure to register the type first, and then create the
4557 constants. That way, doing tsubst_expr for the enumeration
4558 constants won't result in recursive calls here; we'll find
4559 the instantiation and exit above. */
4560 tsubst_enum (template_type, t, arglist);
4561
4562 /* Reset the name of the type, now that CLASSTYPE_TEMPLATE_INFO
4563 is set up. */
4564 if (TREE_CODE (t) != ENUMERAL_TYPE)
4565 DECL_NAME (type_decl) = classtype_mangled_name (t);
4566 if (is_partial_instantiation)
4567 /* If the type makes use of template parameters, the
4568 code that generates debugging information will crash. */
4569 DECL_IGNORED_P (TYPE_STUB_DECL (t)) = 1;
4570
4571 POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, t);
4572 }
4573 timevar_pop (TV_NAME_LOOKUP);
4574 }
注意 template_type 是“ SingleThreaded ”的 RECORD_TYPE 节点,虽然 4364 行的 comp_template_args 发现其实参与 arglist 相同,但我们不是在类作用域中( current_class_type 是 NULL ),我们不得不放弃这个找到的 RECORD_TYPE 节点。
接下来 context 是名字空间“ Loki ”, 4431 行的 tsubst 不做任何事,只是返回这个节点。后面的代码为基类具现创建了 RECORD_TYPE 及相关的节点。这些节点显示如下。最后该 RECORD_TYPE 节点被返回到 instantiate_class_template 的 5439 行。
( 点此打开 )