aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/pt.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp/pt.c')
-rw-r--r--gcc/cp/pt.c541
1 files changed, 441 insertions, 100 deletions
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 9ba46ac..3620253 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -76,7 +76,148 @@ static int comp_template_args PROTO((tree, tree));
static int list_eq PROTO((tree, tree));
static tree get_class_bindings PROTO((tree, tree, tree));
static tree coerce_template_parms PROTO((tree, tree, tree));
-static tree tsubst_enum PROTO((tree, tree *, int));
+static tree tsubst_enum PROTO((tree, tree, int));
+static tree add_to_template_args PROTO((tree, tree));
+
+/* Restore the template parameter context. */
+
+void
+begin_member_template_processing (parms)
+ tree parms;
+{
+ int i;
+
+ ++processing_template_decl;
+ current_template_parms
+ = tree_cons (build_int_2 (0, processing_template_decl),
+ parms, current_template_parms);
+ for (i = 0; i < TREE_VEC_LENGTH (parms); ++i)
+ {
+ tree parm = TREE_VEC_ELT (parms, i);
+
+ switch (TREE_CODE (parm))
+ {
+ case TEMPLATE_TYPE_PARM:
+ pushdecl (TYPE_NAME (parm));
+ break;
+
+ case TEMPLATE_CONST_PARM:
+ pushdecl (parm);
+ break;
+
+ default:
+ my_friendly_abort (0);
+ }
+ }
+}
+
+/* Undo the effects of begin_member_template_processing. */
+
+void
+end_member_template_processing ()
+{
+ if (! processing_template_decl)
+ return;
+
+ --processing_template_decl;
+ current_template_parms = TREE_CHAIN (current_template_parms);
+}
+
+/* Returns non-zero iff T is a member template function. Works if T
+ is either a FUNCTION_DECL or a TEMPLATE_DECL. */
+
+int
+is_member_template (t)
+ tree t;
+{
+ int r = 0;
+
+ if (DECL_FUNCTION_MEMBER_P (t) ||
+ (TREE_CODE (t) == TEMPLATE_DECL &&
+ DECL_FUNCTION_MEMBER_P (DECL_TEMPLATE_RESULT (t))))
+ {
+ tree tmpl = NULL_TREE;
+
+ if (DECL_FUNCTION_TEMPLATE_P (t))
+ tmpl = t;
+ else if (DECL_TEMPLATE_INFO (t)
+ && DECL_FUNCTION_TEMPLATE_P (DECL_TI_TEMPLATE (t)))
+ tmpl = DECL_TI_TEMPLATE (t);
+
+ if (tmpl)
+ {
+ tree parms = DECL_TEMPLATE_PARMS (tmpl);
+ int parm_levels = list_length (parms);
+ int template_class_levels = 0;
+ tree ctx = DECL_CLASS_CONTEXT (t);
+
+ if (CLASSTYPE_TEMPLATE_INFO (ctx))
+ {
+ tree args;
+
+ /* Here, we should really count the number of levels
+ deep ctx is, making sure not to count any levels that
+ are just specializations. Since there are no member
+ template classes yet, we don't have to do all that. */
+
+ if (!CLASSTYPE_TEMPLATE_SPECIALIZATION (ctx))
+ template_class_levels = 1;
+ else
+ {
+ int i;
+
+ args = CLASSTYPE_TI_ARGS (ctx);
+
+ if (args == NULL_TREE)
+ template_class_levels = 1;
+ else
+ for (i = 0; i < TREE_VEC_LENGTH (args); ++i)
+ if (uses_template_parms (TREE_VEC_ELT (args, i)))
+ {
+ template_class_levels++;
+ break;
+ }
+ }
+ }
+
+ if (parm_levels > template_class_levels)
+ r = 1;
+ }
+ }
+
+ return r;
+}
+
+/* Return a new template argument vector which contains all of ARGS,
+ but has as its innermost set of arguments the EXTRA_ARGS. */
+
+tree
+add_to_template_args (args, extra_args)
+ tree args;
+ tree extra_args;
+{
+ tree new_args;
+
+ if (TREE_CODE (TREE_VEC_ELT (args, 0)) != TREE_VEC)
+ {
+ new_args = make_tree_vec (2);
+ TREE_VEC_ELT (new_args, 0) = args;
+ }
+ else
+ {
+ int i;
+
+ new_args = make_tree_vec (TREE_VEC_LENGTH (args) - 1);
+
+ for (i = 0; i < TREE_VEC_LENGTH (args); ++i)
+ TREE_VEC_ELT (new_args, i) = TREE_VEC_ELT (args, i);
+ }
+
+ TREE_VEC_ELT (new_args,
+ TREE_VEC_LENGTH (new_args) - 1) = extra_args;
+
+ return new_args;
+}
/* We've got a template header coming up; push to a new level for storing
the parms. */
@@ -216,7 +357,10 @@ tree
current_template_args ()
{
tree header = current_template_parms;
- tree args = NULL_TREE;
+ int length = list_length (header);
+ tree args = make_tree_vec (length);
+ int l = length;
+
while (header)
{
tree a = copy_node (TREE_VALUE (header));
@@ -224,20 +368,26 @@ current_template_args ()
TREE_TYPE (a) = NULL_TREE;
while (i--)
{
- tree t = TREE_VALUE (TREE_VEC_ELT (a, i));
- if (TREE_CODE (t) == TYPE_DECL)
- t = TREE_TYPE (t);
- else
- t = DECL_INITIAL (t);
+ tree t = TREE_VEC_ELT (a, i);
+
+ /* t will be a list if we are called from within a
+ begin/end_template_parm_list pair, but a vector directly
+ if within a begin/end_member_template_processing pair. */
+ if (TREE_CODE (t) == TREE_LIST)
+ {
+ t = TREE_VALUE (t);
+
+ if (TREE_CODE (t) == TYPE_DECL)
+ t = TREE_TYPE (t);
+ else
+ t = DECL_INITIAL (t);
+ }
+
TREE_VEC_ELT (a, i) = t;
}
- args = tree_cons (TREE_PURPOSE (header), a, args);
+ TREE_VEC_ELT (args, --l) = a;
header = TREE_CHAIN (header);
}
- args = nreverse (args);
-
- /* FIXME Remove this when we support member templates. */
- args = TREE_VALUE (args);
return args;
}
@@ -290,12 +440,15 @@ push_template_decl (decl)
if (! ctx || TYPE_BEING_DEFINED (ctx))
{
tmpl = build_lang_decl (TEMPLATE_DECL, DECL_NAME (decl), NULL_TREE);
- DECL_TEMPLATE_PARMS (tmpl) = TREE_VALUE (current_template_parms);
+ DECL_TEMPLATE_PARMS (tmpl) = current_template_parms;
DECL_CONTEXT (tmpl) = DECL_CONTEXT (decl);
+ if (DECL_LANG_SPECIFIC (decl))
+ DECL_CLASS_CONTEXT (tmpl) = DECL_CLASS_CONTEXT (decl);
}
else
{
tree t;
+ tree a;
if (CLASSTYPE_TEMPLATE_INSTANTIATION (ctx))
cp_error ("must specialize `%#T' before defining member `%#D'",
@@ -309,19 +462,54 @@ push_template_decl (decl)
}
else
tmpl = DECL_TI_TEMPLATE (decl);
+
+ if (is_member_template (tmpl))
+ {
+ a = TREE_VEC_ELT (args, TREE_VEC_LENGTH (args) - 1);
+ t = DECL_INNERMOST_TEMPLATE_PARMS (DECL_TI_TEMPLATE (decl));
+ if (TREE_VEC_LENGTH (t)
+ != TREE_VEC_LENGTH (a))
+ {
+ cp_error ("got %d template parameters for `%#D'",
+ TREE_VEC_LENGTH (a), decl);
+ cp_error (" but %d required", TREE_VEC_LENGTH (t));
+ }
+ if (TREE_VEC_LENGTH (args) > 1)
+ /* Get the template parameters for the enclosing template
+ class. */
+ a = TREE_VEC_ELT (args, TREE_VEC_LENGTH (args) - 2);
+ else
+ a = NULL_TREE;
+ }
+ else
+ a = TREE_VEC_ELT (args, TREE_VEC_LENGTH (args) - 1);
+
+ t = NULL_TREE;
if (CLASSTYPE_TEMPLATE_SPECIALIZATION (ctx))
- t = TREE_VALUE (CLASSTYPE_TI_SPEC_INFO (ctx));
- else
- t = DECL_TEMPLATE_PARMS (CLASSTYPE_TI_TEMPLATE (ctx));
+ {
+ /* When processing an inline member template of a
+ specialized class, there is no CLASSTYPE_TI_SPEC_INFO. */
+ if (CLASSTYPE_TI_SPEC_INFO (ctx))
+ t = TREE_VALUE (CLASSTYPE_TI_SPEC_INFO (ctx));
+ }
+ else if (CLASSTYPE_TEMPLATE_INFO (ctx))
+ t = DECL_INNERMOST_TEMPLATE_PARMS (CLASSTYPE_TI_TEMPLATE (ctx));
+
+ /* There should be template arguments if and only if there is a
+ template class. */
+ my_friendly_assert((a != NULL_TREE) == (t != NULL_TREE), 0);
- if (TREE_VEC_LENGTH (t) != TREE_VEC_LENGTH (args))
+ if (t != NULL_TREE
+ && TREE_VEC_LENGTH (t) != TREE_VEC_LENGTH (a))
{
cp_error ("got %d template parameters for `%#D'",
- TREE_VEC_LENGTH (args), decl);
+ TREE_VEC_LENGTH (a), decl);
cp_error (" but `%#T' has %d", ctx, TREE_VEC_LENGTH (t));
}
}
+ /* Get the innermost set of template arguments. */
+ args = TREE_VEC_ELT (args, TREE_VEC_LENGTH (args) - 1);
DECL_TEMPLATE_RESULT (tmpl) = decl;
TREE_TYPE (tmpl) = TREE_TYPE (decl);
@@ -330,7 +518,7 @@ push_template_decl (decl)
tmpl = pushdecl_top_level (tmpl);
if (primary)
- TREE_TYPE (DECL_TEMPLATE_PARMS (tmpl)) = tmpl;
+ TREE_TYPE (DECL_INNERMOST_TEMPLATE_PARMS (tmpl)) = tmpl;
info = perm_tree_cons (tmpl, args, NULL_TREE);
@@ -345,8 +533,6 @@ push_template_decl (decl)
DECL_TEMPLATE_INFO (decl) = info;
}
-tree tsubst PROTO ((tree, tree*, int, tree));
-
/* Convert all template arguments to their appropriate types, and return
a vector containing the resulting values. If any error occurs, return
error_mark_node. */
@@ -401,10 +587,10 @@ coerce_template_parms (parms, arglist, in_decl)
else if (TREE_CODE (TREE_VALUE (TREE_VEC_ELT (parms, i)))
== TYPE_DECL)
arg = tsubst (TREE_PURPOSE (TREE_VEC_ELT (parms, i)),
- &TREE_VEC_ELT (vec, 0), i, in_decl);
+ vec, i, in_decl);
else
arg = tsubst_expr (TREE_PURPOSE (TREE_VEC_ELT (parms, i)),
- &TREE_VEC_ELT (vec, 0), i, in_decl);
+ vec, i, in_decl);
TREE_VEC_ELT (vec, i) = arg;
}
@@ -460,7 +646,7 @@ coerce_template_parms (parms, arglist, in_decl)
}
else
{
- tree t = tsubst (TREE_TYPE (parm), &TREE_VEC_ELT (vec, 0),
+ tree t = tsubst (TREE_TYPE (parm), vec,
TREE_VEC_LENGTH (vec), in_decl);
if (processing_template_decl)
val = arg;
@@ -656,7 +842,7 @@ classtype_mangled_name (t)
tree name = DECL_NAME (CLASSTYPE_TI_TEMPLATE (t));
char *mangled_name = mangle_class_name_for_template
(IDENTIFIER_POINTER (name),
- DECL_TEMPLATE_PARMS (CLASSTYPE_TI_TEMPLATE (t)),
+ DECL_INNERMOST_TEMPLATE_PARMS (CLASSTYPE_TI_TEMPLATE (t)),
CLASSTYPE_TI_ARGS (t));
tree id = get_identifier (mangled_name);
IDENTIFIER_TEMPLATE (id) = name;
@@ -740,7 +926,7 @@ lookup_template_class (d1, arglist, in_decl)
if (PRIMARY_TEMPLATE_P (template))
{
- parmlist = DECL_TEMPLATE_PARMS (template);
+ parmlist = DECL_INNERMOST_TEMPLATE_PARMS (template);
arglist = coerce_template_parms (parmlist, arglist, template);
if (arglist == error_mark_node)
@@ -1209,7 +1395,7 @@ instantiate_class_template (type)
tree elt;
TREE_VEC_ELT (bases, i) = elt
- = tsubst (TREE_VEC_ELT (pbases, i), &TREE_VEC_ELT (args, 0),
+ = tsubst (TREE_VEC_ELT (pbases, i), args,
TREE_VEC_LENGTH (args), NULL_TREE);
BINFO_INHERITANCE_CHAIN (elt) = binfo;
@@ -1241,7 +1427,7 @@ instantiate_class_template (type)
/* These will add themselves to CLASSTYPE_TAGS for the new type. */
if (TREE_CODE (tag) == ENUMERAL_TYPE)
{
- tree e, newtag = tsubst_enum (tag, &TREE_VEC_ELT (args, 0),
+ tree e, newtag = tsubst_enum (tag, args,
TREE_VEC_LENGTH (args));
*field_chain = grok_enum_decls (newtag, NULL_TREE);
@@ -1252,7 +1438,7 @@ instantiate_class_template (type)
}
}
else
- tsubst (tag, &TREE_VEC_ELT (args, 0),
+ tsubst (tag, args,
TREE_VEC_LENGTH (args), NULL_TREE);
}
@@ -1260,7 +1446,7 @@ instantiate_class_template (type)
for (t = TYPE_FIELDS (pattern); t; t = TREE_CHAIN (t))
if (TREE_CODE (t) != CONST_DECL)
{
- tree r = tsubst (t, &TREE_VEC_ELT (args, 0),
+ tree r = tsubst (t, args,
TREE_VEC_LENGTH (args), NULL_TREE);
if (TREE_CODE (r) == VAR_DECL)
{
@@ -1288,18 +1474,18 @@ instantiate_class_template (type)
DECL_FRIENDLIST (TYPE_MAIN_DECL (type))
= tsubst (DECL_FRIENDLIST (TYPE_MAIN_DECL (pattern)),
- &TREE_VEC_ELT (args, 0), TREE_VEC_LENGTH (args), NULL_TREE);
+ args, TREE_VEC_LENGTH (args), NULL_TREE);
{
tree d = CLASSTYPE_FRIEND_CLASSES (type)
- = tsubst (CLASSTYPE_FRIEND_CLASSES (pattern), &TREE_VEC_ELT (args, 0),
+ = tsubst (CLASSTYPE_FRIEND_CLASSES (pattern), args,
TREE_VEC_LENGTH (args), NULL_TREE);
/* This does injection for friend classes. */
for (; d; d = TREE_CHAIN (d))
TREE_VALUE (d) = xref_tag_from_type (TREE_VALUE (d), NULL_TREE, 1);
- d = tsubst (DECL_TEMPLATE_INJECT (template), &TREE_VEC_ELT (args, 0),
+ d = tsubst (DECL_TEMPLATE_INJECT (template), args,
TREE_VEC_LENGTH (args), NULL_TREE);
for (; d; d = TREE_CHAIN (d))
@@ -1382,7 +1568,7 @@ lookup_nested_type_by_name (ctype, name)
tree
tsubst (t, args, nargs, in_decl)
- tree t, *args;
+ tree t, args;
int nargs;
tree in_decl;
{
@@ -1471,15 +1657,108 @@ tsubst (t, args, nargs, in_decl)
}
case TEMPLATE_TYPE_PARM:
+ case TEMPLATE_CONST_PARM:
{
- tree arg = args[TEMPLATE_TYPE_IDX (t)];
- return cp_build_type_variant
- (arg, TYPE_READONLY (arg) || TYPE_READONLY (t),
- TYPE_VOLATILE (arg) || TYPE_VOLATILE (t));
+ int idx;
+ int level;
+
+ if (TREE_CODE (t) == TEMPLATE_TYPE_PARM)
+ {
+ idx = TEMPLATE_TYPE_IDX (t);
+ level = TEMPLATE_TYPE_LEVEL (t);
+ }
+ else
+ {
+ idx = TEMPLATE_CONST_IDX (t);
+ level = TEMPLATE_CONST_LEVEL (t);
+ }
+
+ if (TREE_VEC_LENGTH (args) > 0)
+ {
+ tree arg = NULL_TREE;
+
+ if (TREE_CODE (TREE_VEC_ELT (args, 0)) == TREE_VEC)
+ {
+ if (TREE_VEC_LENGTH (args) >= level - 1)
+ arg = TREE_VEC_ELT
+ (TREE_VEC_ELT (args, level - 1), idx);
+ }
+ else if (level == 1)
+ arg = TREE_VEC_ELT (args, idx);
+
+ if (arg != NULL_TREE)
+ {
+ if (TREE_CODE (t) == TEMPLATE_TYPE_PARM)
+ return cp_build_type_variant
+ (arg, TYPE_READONLY (arg) || TYPE_READONLY (t),
+ TYPE_VOLATILE (arg) || TYPE_VOLATILE (t));
+ else
+ return arg;
+ }
+ }
+
+ /* If we get here, we must have been looking at a parm for a
+ more deeply nested template. */
+ my_friendly_assert((TREE_CODE (t) == TEMPLATE_CONST_PARM
+ && TEMPLATE_CONST_LEVEL (t) > 1)
+ || (TREE_CODE (t) == TEMPLATE_TYPE_PARM
+ && TEMPLATE_TYPE_LEVEL (t) > 1),
+ 0);
+ return t;
}
- case TEMPLATE_CONST_PARM:
- return args[TEMPLATE_CONST_IDX (t)];
+ 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 new_decl;
+ tree parms;
+ int i;
+
+ /* We might already have an instance of this template. */
+ tree instances = DECL_TEMPLATE_INSTANTIATIONS (t);
+ tree ctx = tsubst (DECL_CLASS_CONTEXT (t), args, nargs, in_decl);
+
+ for (; instances; instances = TREE_CHAIN (instances))
+ if (DECL_CLASS_CONTEXT (TREE_VALUE (instances)) == ctx)
+ return TREE_VALUE (instances);
+
+ /* Make a new template decl. It will be similar to the
+ original, but will record the current template arguments.
+ 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);
+ DECL_CHAIN (tmpl) = NULL_TREE;
+ TREE_CHAIN (tmpl) = NULL_TREE;
+ DECL_TEMPLATE_INFO (tmpl) = build_tree_list (t, args);
+ new_decl = tsubst (decl, args, nargs, in_decl);
+ DECL_RESULT (tmpl) = new_decl;
+ DECL_INITIAL (new_decl) = DECL_INITIAL (decl);
+ DECL_TI_TEMPLATE (new_decl) = tmpl;
+ TREE_TYPE (tmpl) = TREE_TYPE (new_decl);
+ DECL_TEMPLATE_INSTANTIATIONS(tmpl) = 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)
+ = copy_node (DECL_TEMPLATE_PARMS (tmpl));
+ for (parms = DECL_TEMPLATE_PARMS (tmpl);
+ TREE_CHAIN (parms) != NULL_TREE;
+ parms = TREE_CHAIN (parms))
+ TREE_CHAIN (parms) = copy_node (TREE_CHAIN (parms));
+
+ /* Record this partial instantiation. */
+ DECL_TEMPLATE_INSTANTIATIONS (t)
+ = perm_tree_cons (NULL_TREE, tmpl,
+ DECL_TEMPLATE_INSTANTIATIONS (t));
+ return tmpl;
+ }
case FUNCTION_DECL:
{
@@ -1516,7 +1795,7 @@ tsubst (t, args, nargs, in_decl)
/* Do we already have this instantiation? */
if (DECL_TEMPLATE_INFO (t) != NULL_TREE)
{
- tree tmpl = TREE_PURPOSE (DECL_TEMPLATE_INFO (t));
+ tree tmpl = DECL_TI_TEMPLATE (t);
tree decls = DECL_TEMPLATE_INSTANTIATIONS (tmpl);
for (; decls; decls = TREE_CHAIN (decls))
@@ -1622,8 +1901,10 @@ tsubst (t, args, nargs, in_decl)
{
tree tmpl = DECL_TI_TEMPLATE (t);
tree *declsp = &DECL_TEMPLATE_INSTANTIATIONS (tmpl);
- tree argvec = tsubst (TREE_VALUE (DECL_TEMPLATE_INFO (t)),
- args, nargs, in_decl);
+ tree argvec = tsubst (DECL_TI_ARGS (t), args, nargs, in_decl);
+
+ if (DECL_TEMPLATE_INFO (tmpl) && DECL_TI_ARGS (tmpl))
+ argvec = add_to_template_args (DECL_TI_ARGS (tmpl), argvec);
DECL_TEMPLATE_INFO (r) = perm_tree_cons (tmpl, argvec, NULL_TREE);
*declsp = perm_tree_cons (argvec, r, *declsp);
@@ -1727,8 +2008,7 @@ tsubst (t, args, nargs, in_decl)
{
tree tmpl = DECL_TI_TEMPLATE (t);
tree *declsp = &DECL_TEMPLATE_INSTANTIATIONS (tmpl);
- tree argvec = tsubst (TREE_VALUE (DECL_TEMPLATE_INFO (t)),
- args, nargs, in_decl);
+ tree argvec = tsubst (DECL_TI_ARGS (t), args, nargs, in_decl);
DECL_TEMPLATE_INFO (r) = perm_tree_cons (tmpl, argvec, NULL_TREE);
*declsp = perm_tree_cons (argvec, r, *declsp);
@@ -2013,7 +2293,7 @@ do_poplevel ()
tree
tsubst_copy (t, args, nargs, in_decl)
- tree t, *args;
+ tree t, args;
int nargs;
tree in_decl;
{
@@ -2048,6 +2328,12 @@ tsubst_copy (t, args, nargs, in_decl)
mark_used (t);
return t;
+ case TEMPLATE_DECL:
+ if (is_member_template (t))
+ return tsubst (t, args, nargs, in_decl);
+ else
+ return t;
+
#if 0
case IDENTIFIER_NODE:
return do_identifier (t, 0);
@@ -2241,7 +2527,7 @@ tsubst_copy (t, args, nargs, in_decl)
tree
tsubst_expr (t, args, nargs, in_decl)
- tree t, *args;
+ tree t, args;
int nargs;
tree in_decl;
{
@@ -2543,7 +2829,7 @@ tsubst_expr (t, args, nargs, in_decl)
tree
instantiate_template (tmpl, targ_ptr)
- tree tmpl, *targ_ptr;
+ tree tmpl, targ_ptr;
{
tree fndecl;
int i, len;
@@ -2555,12 +2841,12 @@ instantiate_template (tmpl, targ_ptr)
function_maybepermanent_obstack = &permanent_obstack;
my_friendly_assert (TREE_CODE (tmpl) == TEMPLATE_DECL, 283);
- len = TREE_VEC_LENGTH (DECL_TEMPLATE_PARMS (tmpl));
+ len = DECL_NTPARMS (tmpl);
i = len;
while (i--)
{
- tree t = targ_ptr [i];
+ tree t = TREE_VEC_ELT (targ_ptr, i);
if (TREE_CODE_CLASS (TREE_CODE (t)) == 't')
{
tree nt = target_type (t);
@@ -2572,9 +2858,12 @@ instantiate_template (tmpl, targ_ptr)
goto out;
}
}
- targ_ptr[i] = copy_to_permanent (t);
+ TREE_VEC_ELT (targ_ptr, i) = copy_to_permanent (t);
}
+ if (DECL_TEMPLATE_INFO (tmpl) && DECL_TI_ARGS (tmpl))
+ targ_ptr = add_to_template_args (DECL_TI_ARGS (tmpl), targ_ptr);
+
/* substitute template parameters */
fndecl = tsubst (DECL_RESULT (tmpl), targ_ptr, len, tmpl);
@@ -2606,6 +2895,42 @@ overload_template_name (type)
pushdecl_class_level (decl);
}
+/* Like type_unfication but designed specially to handle conversion
+ operators. */
+
+int
+fn_type_unification (fn, targs, args, return_type, strict)
+ tree fn, targs, args, return_type;
+ int strict;
+{
+ int i, dummy = 0;
+ tree fn_arg_types = TYPE_ARG_TYPES (TREE_TYPE (fn));
+ tree decl_arg_types = args;
+
+ my_friendly_assert (TREE_CODE (fn) == TEMPLATE_DECL, 0);
+
+ if (IDENTIFIER_TYPENAME_P (DECL_NAME (fn)))
+ {
+ /* This is a template conversion operator. Use the return types
+ as well as the argument types. */
+ fn_arg_types = tree_cons (NULL_TREE,
+ TREE_TYPE (TREE_TYPE (fn)),
+ fn_arg_types);
+ decl_arg_types = tree_cons (NULL_TREE,
+ return_type,
+ decl_arg_types);
+ }
+
+ i = type_unification (DECL_INNERMOST_TEMPLATE_PARMS (fn),
+ &TREE_VEC_ELT (targs, 0),
+ fn_arg_types,
+ decl_arg_types,
+ &dummy, 0, strict);
+
+ return i;
+}
+
+
/* Type unification.
We have a function template signature with one or more references to
@@ -2718,10 +3043,11 @@ type_unification (tparms, targs, parms, args, nsubsts, subr, strict)
/* Have to back unify here */
arg = TREE_VALUE (arg);
nsubsts = 0;
- ntparms = TREE_VEC_LENGTH (DECL_TEMPLATE_PARMS (arg));
+ ntparms = DECL_NTPARMS (arg);
targs = (tree *) alloca (sizeof (tree) * ntparms);
parm = tree_cons (NULL_TREE, parm, NULL_TREE);
- return type_unification (DECL_TEMPLATE_PARMS (arg), targs,
+ return type_unification (DECL_INNERMOST_TEMPLATE_PARMS (arg),
+ targs,
TYPE_ARG_TYPES (TREE_TYPE (arg)),
parm, &nsubsts, 0, strict);
}
@@ -3022,20 +3348,18 @@ int
more_specialized (pat1, pat2)
tree pat1, pat2;
{
- tree *targs;
+ tree targs;
int winner = 0;
targs = get_bindings (pat1, pat2);
if (targs)
{
- free (targs);
--winner;
}
targs = get_bindings (pat2, pat1);
if (targs)
{
- free (targs);
++winner;
}
@@ -3071,20 +3395,21 @@ more_specialized_class (pat1, pat2)
/* Return the template arguments that will produce the function signature
DECL from the function template FN. */
-tree *
+tree
get_bindings (fn, decl)
tree fn, decl;
{
- int ntparms = TREE_VEC_LENGTH (DECL_TEMPLATE_PARMS (fn));
- tree *targs = (tree *) malloc (sizeof (tree) * ntparms);
- int i, dummy = 0;
- i = type_unification (DECL_TEMPLATE_PARMS (fn), targs,
- TYPE_ARG_TYPES (TREE_TYPE (fn)),
- TYPE_ARG_TYPES (TREE_TYPE (decl)),
- &dummy, 0, 1);
+ int ntparms = DECL_NTPARMS (fn);
+ tree targs = make_tree_vec (ntparms);
+ int i;
+
+ i = fn_type_unification (fn, targs,
+ TYPE_ARG_TYPES (TREE_TYPE (decl)),
+ TREE_TYPE (TREE_TYPE (decl)),
+ 1);
+
if (i == 0)
return targs;
- free (targs);
return 0;
}
@@ -3122,7 +3447,7 @@ tree
most_specialized (fns, decl)
tree fns, decl;
{
- tree fn, champ, *args, *p;
+ tree fn, champ, args, *p;
int fate;
for (p = &fns; *p; )
@@ -3130,7 +3455,6 @@ most_specialized (fns, decl)
args = get_bindings (TREE_VALUE (*p), decl);
if (args)
{
- free (args);
p = &TREE_CHAIN (*p);
}
else
@@ -3234,6 +3558,7 @@ do_decl_instantiation (declspecs, declarator, storage)
tree fn;
tree result = NULL_TREE;
int extern_p = 0;
+ tree templates = NULL_TREE;
if (! DECL_LANG_SPECIFIC (decl))
{
@@ -3261,43 +3586,61 @@ do_decl_instantiation (declspecs, declarator, storage)
fn = IDENTIFIER_GLOBAL_VALUE (name),
fn && DECL_TEMPLATE_INSTANTIATION (fn))
result = fn;
+ else
+ {
+ /* Maybe this is an instantiation of a member template
+ function. */
+ tree ctype = DECL_CONTEXT (decl);
+
+ name = DECL_NAME (decl);
+ fn = lookup_fnfields (TYPE_BINFO (ctype), name, 1);
+ if (fn)
+ fn = TREE_VALUE (fn);
+
+ for (; fn; fn = DECL_CHAIN (fn))
+ if (decls_match (fn, decl) && DECL_DEFER_OUTPUT (fn))
+ {
+ result = fn;
+ break;
+ }
+ else if (TREE_CODE (fn) == TEMPLATE_DECL)
+ templates = decl_tree_cons (NULL_TREE, fn, templates);
+ }
}
else if (name = DECL_NAME (decl), fn = IDENTIFIER_GLOBAL_VALUE (name), fn)
{
- tree templates = NULL_TREE;
for (fn = get_first_fn (fn); fn; fn = DECL_CHAIN (fn))
- if (decls_match (fn, decl)
- && DECL_DEFER_OUTPUT (fn))
+ if (decls_match (fn, decl) && DECL_DEFER_OUTPUT (fn))
{
result = fn;
break;
}
else if (TREE_CODE (fn) == TEMPLATE_DECL)
templates = decl_tree_cons (NULL_TREE, fn, templates);
+ }
- if (! result)
+ if (templates && !result)
+ {
+ tree args;
+ result = most_specialized (templates, decl);
+ if (result == error_mark_node)
{
- tree *args;
- result = most_specialized (templates, decl);
- if (result == error_mark_node)
+ char *str = "candidates are:";
+ cp_error ("ambiguous template instantiation for `%D' requested", decl);
+ for (fn = templates; fn; fn = TREE_CHAIN (fn))
{
- char *str = "candidates are:";
- cp_error ("ambiguous template instantiation for `%D' requested", decl);
- for (fn = templates; fn; fn = TREE_CHAIN (fn))
- {
- cp_error_at ("%s %+#D", str, TREE_VALUE (fn));
- str = " ";
- }
- return;
- }
- else if (result)
- {
- args = get_bindings (result, decl);
- result = instantiate_template (result, args);
- free (args);
+ cp_error_at ("%s %+#D", str, TREE_VALUE (fn));
+ str = " ";
}
+ return;
+ }
+ else if (result)
+ {
+ args = get_bindings (result, decl);
+ result = instantiate_template (result, args);
}
}
+
if (! result)
{
cp_error ("no matching template for `%D' found", decl);
@@ -3477,7 +3820,7 @@ instantiate_decl (d)
{
pushclass (DECL_CONTEXT (d), 2);
DECL_INITIAL (d) = tsubst_expr
- (DECL_INITIAL (pattern), &TREE_VEC_ELT (args, 0),
+ (DECL_INITIAL (pattern), args,
TREE_VEC_LENGTH (args), tmpl);
popclass (1);
}
@@ -3527,7 +3870,7 @@ instantiate_decl (d)
/* Trick tsubst into giving us a new decl in case the template changed. */
save_ti = DECL_TEMPLATE_INFO (pattern);
DECL_TEMPLATE_INFO (pattern) = NULL_TREE;
- td = tsubst (pattern, &TREE_VEC_ELT (args, 0), TREE_VEC_LENGTH (args), tmpl);
+ td = tsubst (pattern, args, TREE_VEC_LENGTH (args), tmpl);
DECL_TEMPLATE_INFO (pattern) = save_ti;
/* And set up DECL_INITIAL, since tsubst doesn't. */
@@ -3535,7 +3878,7 @@ instantiate_decl (d)
{
pushclass (DECL_CONTEXT (d), 2);
DECL_INITIAL (td) = tsubst_expr
- (DECL_INITIAL (pattern), &TREE_VEC_ELT (args, 0),
+ (DECL_INITIAL (pattern), args,
TREE_VEC_LENGTH (args), tmpl);
popclass (1);
}
@@ -3570,7 +3913,7 @@ instantiate_decl (d)
{
store_return_init
(TREE_OPERAND (t, 0),
- tsubst_expr (TREE_OPERAND (t, 1), &TREE_VEC_ELT (args, 0),
+ tsubst_expr (TREE_OPERAND (t, 1), args,
TREE_VEC_LENGTH (args), tmpl));
t = TREE_CHAIN (t);
}
@@ -3591,8 +3934,7 @@ instantiate_decl (d)
keep_next_level ();
my_friendly_assert (TREE_CODE (t) == COMPOUND_STMT, 42);
- tsubst_expr (t, &TREE_VEC_ELT (args, 0),
- TREE_VEC_LENGTH (args), tmpl);
+ tsubst_expr (t, args, TREE_VEC_LENGTH (args), tmpl);
finish_function (lineno, 0, nested);
}
@@ -3613,14 +3955,13 @@ tsubst_chain (t, argvec)
{
if (t)
{
- tree first = tsubst (t, &TREE_VEC_ELT (argvec, 0),
+ tree first = tsubst (t, argvec,
TREE_VEC_LENGTH (argvec), NULL_TREE);
tree last = first;
for (t = TREE_CHAIN (t); t; t = TREE_CHAIN (t))
{
- tree x = tsubst (t, &TREE_VEC_ELT (argvec, 0),
- TREE_VEC_LENGTH (argvec), NULL_TREE);
+ tree x = tsubst (t, argvec, TREE_VEC_LENGTH (argvec), NULL_TREE);
TREE_CHAIN (last) = x;
last = x;
}
@@ -3639,9 +3980,9 @@ tsubst_expr_values (t, argvec)
for (; t; t = TREE_CHAIN (t))
{
- tree pur = tsubst_copy (TREE_PURPOSE (t), &TREE_VEC_ELT (argvec, 0),
+ tree pur = tsubst_copy (TREE_PURPOSE (t), argvec,
TREE_VEC_LENGTH (argvec), NULL_TREE);
- tree val = tsubst_expr (TREE_VALUE (t), &TREE_VEC_ELT (argvec, 0),
+ tree val = tsubst_expr (TREE_VALUE (t), argvec,
TREE_VEC_LENGTH (argvec), NULL_TREE);
*p = build_tree_list (pur, val);
p = &TREE_CHAIN (*p);
@@ -3691,7 +4032,7 @@ add_maybe_template (d, fns)
static tree
tsubst_enum (tag, args, nargs)
- tree tag, *args;
+ tree tag, args;
int nargs;
{
tree newtag = start_enum (TYPE_IDENTIFIER (tag));