static tree most_general_template PROTO((tree));
static void set_mangled_name_for_template_decl PROTO((tree));
static int template_class_depth_real PROTO((tree, int));
+static tree tsubst_aggr_type PROTO((tree, tree, tree, int));
+static tree tsubst_decl PROTO((tree, tree, tree, tree));
/* We use TREE_VECs to hold template arguments. If there is only one
level of template arguments, then the TREE_VEC contains the
{
struct tinst_level *old = current_tinst_level;
+ /* Restore the filename and line number stashed away when we started
+ this instantiation. */
+ lineno = old->line;
+ input_filename = old->file;
+
current_tinst_level = old->next;
old->next = free_tinst_level;
free_tinst_level = old;
for (t = TYPE_FIELDS (pattern); t; t = TREE_CHAIN (t))
if (TREE_CODE (t) != CONST_DECL)
{
- tree r = tsubst (t, args, NULL_TREE);
+ tree r;
+
+ /* The the file and line for this declaration, to assist in
+ error message reporting. Since we called push_tinst_level
+ above, we don't need to restore these. */
+ lineno = DECL_SOURCE_LINE (t);
+ input_filename = DECL_SOURCE_FILE (t);
+
+ r = tsubst (t, args, NULL_TREE);
if (TREE_CODE (r) == VAR_DECL)
{
pending_statics = perm_tree_cons (NULL_TREE, r, pending_statics);
}
}
-/* Take the tree structure T and replace template parameters used therein
- with the argument vector ARGS. IN_DECL is an associated decl for
- diagnostics.
-
- tsubst is used for dealing with types, decls and the like; for
- expressions, use tsubst_expr or tsubst_copy. */
+/* Substitute the ARGS into the T, which is a _DECL. TYPE is the
+ (already computed) substitution of ARGS into TREE_TYPE (T), if
+ appropriate. Return the result of the substitution. IN_DECL is as
+ for tsubst. */
tree
-tsubst (t, args, in_decl)
- tree t, args;
+tsubst_decl (t, args, type, in_decl)
+ tree t;
+ tree args;
+ tree type;
tree in_decl;
{
- tree type;
-
- if (t == NULL_TREE || t == error_mark_node
- || t == integer_type_node
- || t == void_type_node
- || t == char_type_node
- || TREE_CODE (t) == NAMESPACE_DECL)
- return t;
-
- if (TREE_CODE (t) == IDENTIFIER_NODE)
- type = IDENTIFIER_TYPE_VALUE (t);
- else
- type = TREE_TYPE (t);
- if (type == unknown_type_node)
- my_friendly_abort (42);
+ int saved_lineno;
+ char* saved_filename;
+ tree r;
- if (type && TREE_CODE (t) != FUNCTION_DECL
- && TREE_CODE (t) != TYPENAME_TYPE
- && TREE_CODE (t) != TEMPLATE_DECL
- && TREE_CODE (t) != IDENTIFIER_NODE)
- type = tsubst (type, args, in_decl);
+ /* Set the filename and linenumber to improve error-reporting. */
+ saved_lineno = lineno;
+ saved_filename = input_filename;
+ lineno = DECL_SOURCE_LINE (t);
+ input_filename = DECL_SOURCE_FILE (t);
switch (TREE_CODE (t))
{
- case RECORD_TYPE:
- case UNION_TYPE:
- case ENUMERAL_TYPE:
- return tsubst_aggr_type (t, args, in_decl, /*entering_scope=*/0);
-
- case ERROR_MARK:
- case IDENTIFIER_NODE:
- case OP_IDENTIFIER:
- case VOID_TYPE:
- case REAL_TYPE:
- case COMPLEX_TYPE:
- case BOOLEAN_TYPE:
- case INTEGER_CST:
- case REAL_CST:
- case STRING_CST:
- case NAMESPACE_DECL:
- return t;
-
- case INTEGER_TYPE:
- if (t == integer_type_node)
- return t;
-
- if (TREE_CODE (TYPE_MIN_VALUE (t)) == INTEGER_CST
- && TREE_CODE (TYPE_MAX_VALUE (t)) == INTEGER_CST)
- return t;
-
- {
- tree max = TREE_OPERAND (TYPE_MAX_VALUE (t), 0);
- max = tsubst_expr (max, args, in_decl);
- if (processing_template_decl)
- {
- tree itype = make_node (INTEGER_TYPE);
- TYPE_MIN_VALUE (itype) = size_zero_node;
- TYPE_MAX_VALUE (itype) = build_min (MINUS_EXPR, sizetype, max,
- integer_one_node);
- return itype;
- }
-
- max = fold (build_binary_op (MINUS_EXPR, max, integer_one_node, 1));
- return build_index_2_type (size_zero_node, max);
- }
-
- case TEMPLATE_TYPE_PARM:
- case TEMPLATE_TEMPLATE_PARM:
- case TEMPLATE_PARM_INDEX:
- {
- int idx;
- int level;
- int levels;
- tree r = NULL_TREE;
-
- if (TREE_CODE (t) == TEMPLATE_TYPE_PARM
- || TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM)
- {
- idx = TEMPLATE_TYPE_IDX (t);
- level = TEMPLATE_TYPE_LEVEL (t);
- }
- else
- {
- idx = TEMPLATE_PARM_IDX (t);
- level = TEMPLATE_PARM_LEVEL (t);
- }
-
- if (TREE_VEC_LENGTH (args) > 0)
- {
- tree arg = NULL_TREE;
-
- levels = TMPL_ARGS_DEPTH (args);
- if (level <= levels)
- arg = TMPL_ARG (args, level, idx);
-
- if (arg != NULL_TREE)
- {
- if (TREE_CODE (t) == TEMPLATE_TYPE_PARM)
- {
- my_friendly_assert (TREE_CODE_CLASS (TREE_CODE (arg))
- == 't', 0);
- return cp_build_type_variant
- (arg, TYPE_READONLY (arg) || TYPE_READONLY (t),
- TYPE_VOLATILE (arg) || TYPE_VOLATILE (t));
- }
- else if (TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM)
- {
- if (CLASSTYPE_TEMPLATE_INFO (t))
- {
- /* We are processing a type constructed from
- a template template parameter */
- tree argvec = tsubst (CLASSTYPE_TI_ARGS (t),
- args, in_decl);
- tree r;
-
- /* We can get a TEMPLATE_TEMPLATE_PARM here when
- we are resolving nested-types in the signature of
- a member function templates.
- Otherwise ARG is a TEMPLATE_DECL and is the real
- template to be instantiated. */
- if (TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM)
- arg = TYPE_NAME (arg);
-
- r = lookup_template_class (DECL_NAME (arg),
- argvec, in_decl,
- DECL_CONTEXT (arg),
- /*entering_scope=*/0);
- return cp_build_type_variant (r, TYPE_READONLY (t),
- TYPE_VOLATILE (t));
- }
- else
- /* We are processing a template argument list. */
- return arg;
- }
- else
- return arg;
- }
- }
-
- if (level == 1)
- /* This can happen during the attempted tsubst'ing in
- unify. This means that we don't yet have any information
- about the template parameter in question. */
- return t;
-
- /* If we get here, we must have been looking at a parm for a
- more deeply nested template. Make a new version of this
- template parameter, but with a lower level. */
- switch (TREE_CODE (t))
- {
- case TEMPLATE_TYPE_PARM:
- case TEMPLATE_TEMPLATE_PARM:
- r = copy_node (t);
- TEMPLATE_TYPE_PARM_INDEX (r)
- = reduce_template_parm_level (TEMPLATE_TYPE_PARM_INDEX (t),
- r, levels);
- TYPE_STUB_DECL (r) = TYPE_NAME (r) = TEMPLATE_TYPE_DECL (r);
- TYPE_MAIN_VARIANT (r) = r;
- TYPE_POINTER_TO (r) = NULL_TREE;
- TYPE_REFERENCE_TO (r) = NULL_TREE;
-
- if (TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM
- && CLASSTYPE_TEMPLATE_INFO (t))
- {
- tree argvec = tsubst (CLASSTYPE_TI_ARGS (t), args, in_decl);
- CLASSTYPE_TEMPLATE_INFO (r)
- = perm_tree_cons (TYPE_NAME (t), argvec, NULL_TREE);
- }
- break;
-
- case TEMPLATE_PARM_INDEX:
- r = reduce_template_parm_level (t, type, levels);
- break;
-
- default:
- my_friendly_abort (0);
- }
-
- return r;
- }
-
case TEMPLATE_DECL:
{
/* We can get here when processing a member template function
of a template class. */
- tree tmpl;
tree decl = DECL_TEMPLATE_RESULT (t);
tree parms;
tree* new_parms;
spec = retrieve_specialization (t, full_args);
if (spec != NULL_TREE)
- return spec;
+ {
+ r = spec;
+ break;
+ }
}
/* Make a new template decl. It will be similar to the
We also create a new function declaration, which is just
like the old one, but points to this new template, rather
than the old one. */
- tmpl = copy_node (t);
- copy_lang_decl (tmpl);
- my_friendly_assert (DECL_LANG_SPECIFIC (tmpl) != 0, 0);
- TREE_CHAIN (tmpl) = NULL_TREE;
+ r = copy_node (t);
+ copy_lang_decl (r);
+ my_friendly_assert (DECL_LANG_SPECIFIC (r) != 0, 0);
+ TREE_CHAIN (r) = NULL_TREE;
if (is_template_template_parm)
{
tree new_decl = tsubst (decl, args, in_decl);
- DECL_RESULT (tmpl) = new_decl;
- TREE_TYPE (tmpl) = TREE_TYPE (new_decl);
- return tmpl;
+ DECL_RESULT (r) = new_decl;
+ TREE_TYPE (r) = TREE_TYPE (new_decl);
+ break;
}
- DECL_CONTEXT (tmpl)
+ DECL_CONTEXT (r)
= tsubst_aggr_type (DECL_CONTEXT (t), args, in_decl,
/*entering_scope=*/1);
- DECL_CLASS_CONTEXT (tmpl)
+ DECL_CLASS_CONTEXT (r)
= tsubst_aggr_type (DECL_CLASS_CONTEXT (t), args, in_decl,
/*entering_scope=*/1);
- DECL_TEMPLATE_INFO (tmpl) = build_tree_list (t, args);
+ DECL_TEMPLATE_INFO (r) = build_tree_list (t, args);
if (TREE_CODE (decl) == TYPE_DECL)
{
tree new_type = tsubst (TREE_TYPE (t), args, in_decl);
- TREE_TYPE (tmpl) = new_type;
- CLASSTYPE_TI_TEMPLATE (new_type) = tmpl;
- DECL_RESULT (tmpl) = TYPE_MAIN_DECL (new_type);
- DECL_TI_ARGS (tmpl) = CLASSTYPE_TI_ARGS (new_type);
+ TREE_TYPE (r) = new_type;
+ CLASSTYPE_TI_TEMPLATE (new_type) = r;
+ DECL_RESULT (r) = TYPE_MAIN_DECL (new_type);
+ DECL_TI_ARGS (r) = CLASSTYPE_TI_ARGS (new_type);
}
else
{
tree new_decl = tsubst (decl, args, in_decl);
- DECL_RESULT (tmpl) = new_decl;
- DECL_TI_TEMPLATE (new_decl) = tmpl;
- TREE_TYPE (tmpl) = TREE_TYPE (new_decl);
- DECL_TI_ARGS (tmpl) = DECL_TI_ARGS (new_decl);
+ DECL_RESULT (r) = new_decl;
+ DECL_TI_TEMPLATE (new_decl) = r;
+ TREE_TYPE (r) = TREE_TYPE (new_decl);
+ DECL_TI_ARGS (r) = DECL_TI_ARGS (new_decl);
}
- SET_DECL_IMPLICIT_INSTANTIATION (tmpl);
- DECL_TEMPLATE_INSTANTIATIONS (tmpl) = NULL_TREE;
- DECL_TEMPLATE_SPECIALIZATIONS (tmpl) = NULL_TREE;
+ SET_DECL_IMPLICIT_INSTANTIATION (r);
+ DECL_TEMPLATE_INSTANTIATIONS (r) = NULL_TREE;
+ DECL_TEMPLATE_SPECIALIZATIONS (r) = NULL_TREE;
/* The template parameters for this new template are all the
template parameters for the old template, except the
outermost level of parameters. */
- DECL_TEMPLATE_PARMS (tmpl)
+ DECL_TEMPLATE_PARMS (r)
= tsubst_template_parms (DECL_TEMPLATE_PARMS (t), args);
if (PRIMARY_TEMPLATE_P (t))
- DECL_PRIMARY_TEMPLATE (tmpl) = tmpl;
+ DECL_PRIMARY_TEMPLATE (r) = r;
/* We don't partially instantiate partial specializations. */
if (TREE_CODE (decl) == TYPE_DECL)
- return tmpl;
+ break;
for (spec = DECL_TEMPLATE_SPECIALIZATIONS (t);
spec != NULL_TREE;
new_fn = tsubst (DECL_RESULT (most_general_template (fn)),
spec_args, in_decl);
DECL_TI_TEMPLATE (new_fn) = fn;
- register_specialization (new_fn, tmpl,
+ register_specialization (new_fn, r,
innermost_args (spec_args));
}
/* Record this partial instantiation. */
- register_specialization (tmpl, t,
- DECL_TI_ARGS (DECL_RESULT (tmpl)));
+ register_specialization (r, t,
+ DECL_TI_ARGS (DECL_RESULT (r)));
- return tmpl;
}
+ break;
case FUNCTION_DECL:
{
- tree r = NULL_TREE;
tree ctx;
tree argvec;
tree gen_tmpl;
/* Check to see if we already have this specialization. */
spec = retrieve_specialization (gen_tmpl, argvec);
if (spec)
- return spec;
+ {
+ r = spec;
+ break;
+ }
}
else
{
== NULL_TREE))
SET_IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (r), r);
}
-
- return r;
}
+ break;
case PARM_DECL:
{
- tree r = copy_node (t);
+ r = copy_node (t);
TREE_TYPE (r) = type;
if (TREE_CODE (DECL_INITIAL (r)) != TEMPLATE_PARM_INDEX)
DECL_INITIAL (r) = TREE_TYPE (r);
#endif
if (TREE_CHAIN (t))
TREE_CHAIN (r) = tsubst (TREE_CHAIN (t), args, TREE_CHAIN (t));
- return r;
}
+ break;
case FIELD_DECL:
{
- tree r = copy_node (t);
+ r = copy_node (t);
TREE_TYPE (r) = type;
copy_lang_decl (r);
#if 0
TREE_CHAIN (r) = NULL_TREE;
if (TREE_CODE (type) == VOID_TYPE)
cp_error_at ("instantiation of `%D' as type void", r);
- return r;
}
+ break;
case USING_DECL:
{
- tree r = copy_node (t);
+ r = copy_node (t);
DECL_INITIAL (r)
= tsubst_copy (DECL_INITIAL (t), args, in_decl);
TREE_CHAIN (r) = NULL_TREE;
- return r;
}
+ break;
case VAR_DECL:
{
- tree r;
tree argvec;
tree gen_tmpl;
tree spec;
spec = retrieve_specialization (gen_tmpl, argvec);
if (spec)
- return spec;
+ {
+ r = spec;
+ break;
+ }
r = copy_node (t);
TREE_TYPE (r) = type;
TREE_CHAIN (r) = NULL_TREE;
if (TREE_CODE (type) == VOID_TYPE)
cp_error_at ("instantiation of `%D' as type void", r);
- return r;
}
+ break;
case TYPE_DECL:
if (t == TYPE_NAME (TREE_TYPE (t)))
- return TYPE_NAME (type);
+ r = TYPE_NAME (type);
+ else
+ {
+ r = copy_node (t);
+ TREE_TYPE (r) = type;
+ DECL_CONTEXT (r) = current_class_type;
+ TREE_CHAIN (r) = NULL_TREE;
+ }
+ break;
+
+ default:
+ my_friendly_abort (0);
+ }
+
+ /* Restore the file and line information. */
+ lineno = saved_lineno;
+ input_filename = saved_filename;
+
+ return r;
+}
+
+
+/* Take the tree structure T and replace template parameters used therein
+ with the argument vector ARGS. IN_DECL is an associated decl for
+ diagnostics.
+
+ tsubst is used for dealing with types, decls and the like; for
+ expressions, use tsubst_expr or tsubst_copy. */
+
+tree
+tsubst (t, args, in_decl)
+ tree t, args;
+ tree in_decl;
+{
+ tree type;
+
+ if (t == NULL_TREE || t == error_mark_node
+ || t == integer_type_node
+ || t == void_type_node
+ || t == char_type_node
+ || TREE_CODE (t) == NAMESPACE_DECL)
+ return t;
+
+ if (TREE_CODE (t) == IDENTIFIER_NODE)
+ type = IDENTIFIER_TYPE_VALUE (t);
+ else
+ type = TREE_TYPE (t);
+ if (type == unknown_type_node)
+ my_friendly_abort (42);
+
+ if (type && TREE_CODE (t) != FUNCTION_DECL
+ && TREE_CODE (t) != TYPENAME_TYPE
+ && TREE_CODE (t) != TEMPLATE_DECL
+ && TREE_CODE (t) != IDENTIFIER_NODE)
+ type = tsubst (type, args, in_decl);
+
+ if (TREE_CODE_CLASS (TREE_CODE (t)) == 'd')
+ return tsubst_decl (t, args, type, in_decl);
+
+ switch (TREE_CODE (t))
+ {
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ case ENUMERAL_TYPE:
+ return tsubst_aggr_type (t, args, in_decl, /*entering_scope=*/0);
+
+ case ERROR_MARK:
+ case IDENTIFIER_NODE:
+ case OP_IDENTIFIER:
+ case VOID_TYPE:
+ case REAL_TYPE:
+ case COMPLEX_TYPE:
+ case BOOLEAN_TYPE:
+ case INTEGER_CST:
+ case REAL_CST:
+ case STRING_CST:
+ return t;
+
+ case INTEGER_TYPE:
+ if (t == integer_type_node)
+ return t;
+
+ if (TREE_CODE (TYPE_MIN_VALUE (t)) == INTEGER_CST
+ && TREE_CODE (TYPE_MAX_VALUE (t)) == INTEGER_CST)
+ return t;
{
- tree r = copy_node (t);
- TREE_TYPE (r) = type;
- DECL_CONTEXT (r) = current_class_type;
- TREE_CHAIN (r) = NULL_TREE;
+ tree max = TREE_OPERAND (TYPE_MAX_VALUE (t), 0);
+ max = tsubst_expr (max, args, in_decl);
+ if (processing_template_decl)
+ {
+ tree itype = make_node (INTEGER_TYPE);
+ TYPE_MIN_VALUE (itype) = size_zero_node;
+ TYPE_MAX_VALUE (itype) = build_min (MINUS_EXPR, sizetype, max,
+ integer_one_node);
+ return itype;
+ }
+
+ max = fold (build_binary_op (MINUS_EXPR, max, integer_one_node, 1));
+ return build_index_2_type (size_zero_node, max);
+ }
+
+ case TEMPLATE_TYPE_PARM:
+ case TEMPLATE_TEMPLATE_PARM:
+ case TEMPLATE_PARM_INDEX:
+ {
+ int idx;
+ int level;
+ int levels;
+ tree r = NULL_TREE;
+
+ if (TREE_CODE (t) == TEMPLATE_TYPE_PARM
+ || TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM)
+ {
+ idx = TEMPLATE_TYPE_IDX (t);
+ level = TEMPLATE_TYPE_LEVEL (t);
+ }
+ else
+ {
+ idx = TEMPLATE_PARM_IDX (t);
+ level = TEMPLATE_PARM_LEVEL (t);
+ }
+
+ if (TREE_VEC_LENGTH (args) > 0)
+ {
+ tree arg = NULL_TREE;
+
+ levels = TMPL_ARGS_DEPTH (args);
+ if (level <= levels)
+ arg = TMPL_ARG (args, level, idx);
+
+ if (arg != NULL_TREE)
+ {
+ if (TREE_CODE (t) == TEMPLATE_TYPE_PARM)
+ {
+ my_friendly_assert (TREE_CODE_CLASS (TREE_CODE (arg))
+ == 't', 0);
+ return cp_build_type_variant
+ (arg, TYPE_READONLY (arg) || TYPE_READONLY (t),
+ TYPE_VOLATILE (arg) || TYPE_VOLATILE (t));
+ }
+ else if (TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM)
+ {
+ if (CLASSTYPE_TEMPLATE_INFO (t))
+ {
+ /* We are processing a type constructed from
+ a template template parameter */
+ tree argvec = tsubst (CLASSTYPE_TI_ARGS (t),
+ args, in_decl);
+ tree r;
+
+ /* We can get a TEMPLATE_TEMPLATE_PARM here when
+ we are resolving nested-types in the signature of
+ a member function templates.
+ Otherwise ARG is a TEMPLATE_DECL and is the real
+ template to be instantiated. */
+ if (TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM)
+ arg = TYPE_NAME (arg);
+
+ r = lookup_template_class (DECL_NAME (arg),
+ argvec, in_decl,
+ DECL_CONTEXT (arg),
+ /*entering_scope=*/0);
+ return cp_build_type_variant (r, TYPE_READONLY (t),
+ TYPE_VOLATILE (t));
+ }
+ else
+ /* We are processing a template argument list. */
+ return arg;
+ }
+ else
+ return arg;
+ }
+ }
+
+ if (level == 1)
+ /* This can happen during the attempted tsubst'ing in
+ unify. This means that we don't yet have any information
+ about the template parameter in question. */
+ return t;
+
+ /* If we get here, we must have been looking at a parm for a
+ more deeply nested template. Make a new version of this
+ template parameter, but with a lower level. */
+ switch (TREE_CODE (t))
+ {
+ case TEMPLATE_TYPE_PARM:
+ case TEMPLATE_TEMPLATE_PARM:
+ r = copy_node (t);
+ TEMPLATE_TYPE_PARM_INDEX (r)
+ = reduce_template_parm_level (TEMPLATE_TYPE_PARM_INDEX (t),
+ r, levels);
+ TYPE_STUB_DECL (r) = TYPE_NAME (r) = TEMPLATE_TYPE_DECL (r);
+ TYPE_MAIN_VARIANT (r) = r;
+ TYPE_POINTER_TO (r) = NULL_TREE;
+ TYPE_REFERENCE_TO (r) = NULL_TREE;
+
+ if (TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM
+ && CLASSTYPE_TEMPLATE_INFO (t))
+ {
+ tree argvec = tsubst (CLASSTYPE_TI_ARGS (t), args, in_decl);
+ CLASSTYPE_TEMPLATE_INFO (r)
+ = perm_tree_cons (TYPE_NAME (t), argvec, NULL_TREE);
+ }
+ break;
+
+ case TEMPLATE_PARM_INDEX:
+ r = reduce_template_parm_level (t, type, levels);
+ break;
+
+ default:
+ my_friendly_abort (0);
+ }
+
return r;
- }
+ }
case TREE_LIST:
{
tree ctx = tsubst_aggr_type (TYPE_CONTEXT (t), args, in_decl,
/*entering_scope=*/1);
tree f = tsubst_copy (TYPENAME_TYPE_FULLNAME (t), args, in_decl);
+
+ /* Normally, make_typename_type does not require that the CTX
+ have complete type in order to allow things like:
+
+ template <class T> struct S { typename S<T>::X Y; };
+
+ But, such constructs have already been resolved by this
+ point, so here CTX really should have complete type, unless
+ it's a partial instantiation. */
+ if (!uses_template_parms (ctx)
+ && !complete_type_or_else (ctx))
+ return error_mark_node;
+
f = make_typename_type (ctx, f);
return cp_build_type_variant
(f, TYPE_READONLY (f) || TYPE_READONLY (t),