pt.c (tsubst): Decrease the template-level of TEMPLATE_TEMPLATE_PARMS.

* pt.c (tsubst): Decrease the template-level of
	 TEMPLATE_TEMPLATE_PARMS.  Likewise for the DECL_INITIAL of a
	 TEMPLATE_PARM_INDEX.
	 (template_decl_level): New function.
	 (unify): Make sure to record unifications for template
	 parameters, even when the parameters exactly match the arguments.
	 Combine duplicated code for TEMPLATE_TEMPLATE_PARMs and
	 TEMPLATE_TYPE_PARMS.  Don't try to unify template parameters that
	 aren't from the level we're currently working on.

From-SVN: r19378
This commit is contained in:
Mark Mitchell 1998-04-22 21:02:01 +00:00 committed by Mark Mitchell
parent 693e265fc0
commit db2767b644
2 changed files with 143 additions and 90 deletions

View File

@ -4,6 +4,16 @@ Wed Apr 22 13:24:48 1998 Mark Mitchell <mmitchell@usa.net>
the DECL_RESULTs of a member TEMPLATE_DECL, not just the the DECL_RESULTs of a member TEMPLATE_DECL, not just the
TEMPLATE_DECL. TEMPLATE_DECL.
* pt.c (tsubst): Decrease the template-level of
TEMPLATE_TEMPLATE_PARMS. Likewise for the DECL_INITIAL of a
TEMPLATE_PARM_INDEX.
(template_decl_level): New function.
(unify): Make sure to record unifications for template
parameters, even when the parameters exactly match the arguments.
Combine duplicated code for TEMPLATE_TEMPLATE_PARMs and
TEMPLATE_TYPE_PARMS. Don't try to unify template parameters that
aren't from the level we're currently working on.
Tue Apr 21 22:00:04 1998 Mark Mitchell <mmitchell@usa.net> Tue Apr 21 22:00:04 1998 Mark Mitchell <mmitchell@usa.net>
* errfn.c (cp_thing): Use xrealloc, not xmalloc, to copy memory. * errfn.c (cp_thing): Use xrealloc, not xmalloc, to copy memory.

View File

@ -3944,17 +3944,15 @@ tsubst (t, args, in_decl)
tree parms; tree parms;
tree* new_parms; tree* new_parms;
tree spec; tree spec;
int is_template_template_parm = DECL_TEMPLATE_TEMPLATE_PARM_P (t);
if (TREE_CODE (decl) == TYPE_DECL if (!is_template_template_parm)
&& TREE_CODE (TREE_TYPE (decl)) == TEMPLATE_TEMPLATE_PARM) {
/* There is no tsubst'ing to be done in a template template /* We might already have an instance of this template. */
parameter. */ spec = retrieve_specialization (t, args);
return t; if (spec != NULL_TREE)
return spec;
/* We might already have an instance of this template. */ }
spec = retrieve_specialization (t, args);
if (spec != NULL_TREE)
return spec;
/* Make a new template decl. It will be similar to the /* Make a new template decl. It will be similar to the
original, but will record the current template arguments. original, but will record the current template arguments.
@ -3966,6 +3964,15 @@ tsubst (t, args, in_decl)
my_friendly_assert (DECL_LANG_SPECIFIC (tmpl) != 0, 0); my_friendly_assert (DECL_LANG_SPECIFIC (tmpl) != 0, 0);
DECL_CHAIN (tmpl) = NULL_TREE; DECL_CHAIN (tmpl) = NULL_TREE;
TREE_CHAIN (tmpl) = NULL_TREE; TREE_CHAIN (tmpl) = 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_CONTEXT (tmpl) = tsubst (DECL_CONTEXT (t), DECL_CONTEXT (tmpl) = tsubst (DECL_CONTEXT (t),
args, in_decl); args, in_decl);
DECL_CLASS_CONTEXT (tmpl) = tsubst (DECL_CLASS_CONTEXT (t), DECL_CLASS_CONTEXT (tmpl) = tsubst (DECL_CLASS_CONTEXT (t),
@ -4311,7 +4318,11 @@ tsubst (t, args, in_decl)
{ {
tree r = copy_node (t); tree r = copy_node (t);
TREE_TYPE (r) = type; TREE_TYPE (r) = type;
DECL_INITIAL (r) = TREE_TYPE (r); if (TREE_CODE (DECL_INITIAL (r)) != TEMPLATE_PARM_INDEX)
DECL_INITIAL (r) = TREE_TYPE (r);
else
DECL_INITIAL (r) = tsubst (DECL_INITIAL (r), args, in_decl);
DECL_CONTEXT (r) = NULL_TREE; DECL_CONTEXT (r) = NULL_TREE;
#ifdef PROMOTE_PROTOTYPES #ifdef PROMOTE_PROTOTYPES
if ((TREE_CODE (type) == INTEGER_TYPE if ((TREE_CODE (type) == INTEGER_TYPE
@ -5565,6 +5576,27 @@ type_unification_real (tparms, targs, parms, args, subr,
return 0; return 0;
} }
/* Returns the level of DECL, which declares a template parameter. */
static int
template_decl_level (decl)
tree decl;
{
switch (TREE_CODE (decl))
{
case TYPE_DECL:
case TEMPLATE_DECL:
return TEMPLATE_TYPE_LEVEL (TREE_TYPE (decl));
case PARM_DECL:
return TEMPLATE_PARM_LEVEL (DECL_INITIAL (decl));
default:
my_friendly_abort (0);
break;
}
}
/* Tail recursion is your friend. */ /* Tail recursion is your friend. */
static int static int
@ -5575,6 +5607,7 @@ unify (tparms, targs, ntparms, parm, arg, strict, explicit_mask)
{ {
int idx; int idx;
tree targ; tree targ;
tree tparm;
/* I don't think this will do the right thing with respect to types. /* I don't think this will do the right thing with respect to types.
But the only case I've seen it in so far has been array bounds, where But the only case I've seen it in so far has been array bounds, where
@ -5587,7 +5620,11 @@ unify (tparms, targs, ntparms, parm, arg, strict, explicit_mask)
return 1; return 1;
if (arg == unknown_type_node) if (arg == unknown_type_node)
return 1; return 1;
if (arg == parm) /* If PARM uses template parameters, then we can't bail out here,
even in ARG == PARM, since we won't record unifications for the
template parameters. We might need them if we're trying to
figure out which of two things is more specialized. */
if (arg == parm && !uses_template_parms (parm))
return 0; return 0;
/* We can't remove cv-quals when strict. */ /* We can't remove cv-quals when strict. */
@ -5606,53 +5643,24 @@ unify (tparms, targs, ntparms, parm, arg, strict, explicit_mask)
return 0; return 0;
case TEMPLATE_TYPE_PARM: case TEMPLATE_TYPE_PARM:
idx = TEMPLATE_TYPE_IDX (parm);
targ = TREE_VEC_ELT (targs, idx);
/* Check for mixed types and values. */
if (TREE_CODE (TREE_VALUE (TREE_VEC_ELT (tparms, idx))) != TYPE_DECL)
return 1;
if (!strict && targ != NULL_TREE
&& explicit_mask && explicit_mask[idx])
/* An explicit template argument. Don't even try to match
here; the overload resolution code will manage check to
see whether the call is legal. */
return 0;
if (strict && (TYPE_READONLY (arg) < TYPE_READONLY (parm)
|| TYPE_VOLATILE (arg) < TYPE_VOLATILE (parm)))
return 1;
#if 0
/* Template type parameters cannot contain cv-quals; i.e.
template <class T> void f (T& a, T& b) will not generate
void f (const int& a, const int& b). */
if (TYPE_READONLY (arg) > TYPE_READONLY (parm)
|| TYPE_VOLATILE (arg) > TYPE_VOLATILE (parm))
return 1;
arg = TYPE_MAIN_VARIANT (arg);
#else
{
int constp = TYPE_READONLY (arg) > TYPE_READONLY (parm);
int volatilep = TYPE_VOLATILE (arg) > TYPE_VOLATILE (parm);
arg = cp_build_type_variant (arg, constp, volatilep);
}
#endif
/* Simple cases: Value already set, does match or doesn't. */
if (targ != NULL_TREE
&& (comptypes (targ, arg, 1)
|| (explicit_mask && explicit_mask[idx])))
return 0;
else if (targ)
return 1;
TREE_VEC_ELT (targs, idx) = arg;
return 0;
case TEMPLATE_TEMPLATE_PARM: case TEMPLATE_TEMPLATE_PARM:
tparm = TREE_VALUE (TREE_VEC_ELT (tparms, 0));
if (TEMPLATE_TYPE_LEVEL (parm)
!= template_decl_level (tparm))
/* The PARM is not one we're trying to unify. Just check
to see if it matches ARG. */
return (TREE_CODE (arg) == TREE_CODE (parm)
&& comptypes (parm, arg, 1) == 0) ? 0 : 1;
idx = TEMPLATE_TYPE_IDX (parm); idx = TEMPLATE_TYPE_IDX (parm);
targ = TREE_VEC_ELT (targs, idx); targ = TREE_VEC_ELT (targs, idx);
tparm = TREE_VALUE (TREE_VEC_ELT (tparms, idx));
/* Check for mixed types and values. */ /* Check for mixed types and values. */
if (TREE_CODE (TREE_VALUE (TREE_VEC_ELT (tparms, idx))) != TEMPLATE_DECL) if ((TREE_CODE (parm) == TEMPLATE_TYPE_PARM
&& TREE_CODE (tparm) != TYPE_DECL)
|| (TREE_CODE (parm) == TEMPLATE_TEMPLATE_PARM
&& TREE_CODE (tparm) != TEMPLATE_DECL))
return 1; return 1;
if (!strict && targ != NULL_TREE if (!strict && targ != NULL_TREE
@ -5662,51 +5670,76 @@ unify (tparms, targs, ntparms, parm, arg, strict, explicit_mask)
see whether the call is legal. */ see whether the call is legal. */
return 0; return 0;
if (CLASSTYPE_TEMPLATE_INFO (parm)) if (TREE_CODE (parm) == TEMPLATE_TEMPLATE_PARM)
{ {
/* We arrive here when PARM does not involve template if (CLASSTYPE_TEMPLATE_INFO (parm))
specialization. */ {
/* We arrive here when PARM does not involve template
specialization. */
/* ARG must be constructed from a template class. */ /* ARG must be constructed from a template class. */
if (TREE_CODE (arg) != RECORD_TYPE || !CLASSTYPE_TEMPLATE_INFO (arg)) if (TREE_CODE (arg) != RECORD_TYPE || !CLASSTYPE_TEMPLATE_INFO (arg))
return 1; return 1;
{ {
tree parmtmpl = CLASSTYPE_TI_TEMPLATE (parm); tree parmtmpl = CLASSTYPE_TI_TEMPLATE (parm);
tree parmvec = CLASSTYPE_TI_ARGS (parm); tree parmvec = CLASSTYPE_TI_ARGS (parm);
tree argvec = CLASSTYPE_TI_ARGS (arg); tree argvec = CLASSTYPE_TI_ARGS (arg);
tree argtmplvec tree argtmplvec
= DECL_INNERMOST_TEMPLATE_PARMS (CLASSTYPE_TI_TEMPLATE (arg)); = DECL_INNERMOST_TEMPLATE_PARMS (CLASSTYPE_TI_TEMPLATE (arg));
int i; int i;
/* The parameter and argument roles have to be switched here /* The parameter and argument roles have to be switched here
in order to handle default arguments properly. For example, in order to handle default arguments properly. For example,
template<template <class> class TT> void f(TT<int>) template<template <class> class TT> void f(TT<int>)
should be able to accept vector<int> which comes from should be able to accept vector<int> which comes from
template <class T, class Allcator = allocator> template <class T, class Allcator = allocator>
class vector. */ class vector. */
if (coerce_template_parms (argtmplvec, parmvec, parmtmpl, 1, 1, 0) if (coerce_template_parms (argtmplvec, parmvec, parmtmpl, 1, 1, 0)
== error_mark_node) == error_mark_node)
return 1;
/* Deduce arguments T, i from TT<T> or TT<i>. */
for (i = 0; i < TREE_VEC_LENGTH (parmvec); ++i)
{
tree t = TREE_VEC_ELT (parmvec, i);
if (TREE_CODE (t) != TEMPLATE_TYPE_PARM
&& TREE_CODE (t) != TEMPLATE_TEMPLATE_PARM
&& TREE_CODE (t) != TEMPLATE_PARM_INDEX)
continue;
/* This argument can be deduced. */
if (unify (tparms, targs, ntparms, t,
TREE_VEC_ELT (argvec, i), strict, explicit_mask))
return 1; return 1;
/* Deduce arguments T, i from TT<T> or TT<i>. */
for (i = 0; i < TREE_VEC_LENGTH (parmvec); ++i)
{
tree t = TREE_VEC_ELT (parmvec, i);
if (TREE_CODE (t) != TEMPLATE_TYPE_PARM
&& TREE_CODE (t) != TEMPLATE_TEMPLATE_PARM
&& TREE_CODE (t) != TEMPLATE_PARM_INDEX)
continue;
/* This argument can be deduced. */
if (unify (tparms, targs, ntparms, t,
TREE_VEC_ELT (argvec, i), strict, explicit_mask))
return 1;
}
} }
arg = CLASSTYPE_TI_TEMPLATE (arg);
}
}
else
{
if (strict && (TYPE_READONLY (arg) < TYPE_READONLY (parm)
|| TYPE_VOLATILE (arg) < TYPE_VOLATILE (parm)))
return 1;
#if 0
/* Template type parameters cannot contain cv-quals; i.e.
template <class T> void f (T& a, T& b) will not generate
void f (const int& a, const int& b). */
if (TYPE_READONLY (arg) > TYPE_READONLY (parm)
|| TYPE_VOLATILE (arg) > TYPE_VOLATILE (parm))
return 1;
arg = TYPE_MAIN_VARIANT (arg);
#else
{
int constp = TYPE_READONLY (arg) > TYPE_READONLY (parm);
int volatilep = TYPE_VOLATILE (arg) > TYPE_VOLATILE (parm);
arg = cp_build_type_variant (arg, constp, volatilep);
} }
arg = CLASSTYPE_TI_TEMPLATE (arg); #endif
} }
/* Simple cases: Value already set, does match or doesn't. */ /* Simple cases: Value already set, does match or doesn't. */
@ -5720,8 +5753,18 @@ unify (tparms, targs, ntparms, parm, arg, strict, explicit_mask)
return 0; return 0;
case TEMPLATE_PARM_INDEX: case TEMPLATE_PARM_INDEX:
tparm = TREE_VALUE (TREE_VEC_ELT (tparms, 0));
if (TEMPLATE_PARM_LEVEL (parm)
!= template_decl_level (tparm))
/* The PARM is not one we're trying to unify. Just check
to see if it matches ARG. */
return (TREE_CODE (arg) == TREE_CODE (parm)
&& cp_tree_equal (parm, arg) == 0) ? 0 : 1;
idx = TEMPLATE_PARM_IDX (parm); idx = TEMPLATE_PARM_IDX (parm);
targ = TREE_VEC_ELT (targs, idx); targ = TREE_VEC_ELT (targs, idx);
if (targ) if (targ)
{ {
int i = cp_tree_equal (targ, arg); int i = cp_tree_equal (targ, arg);