This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
PATCH to fix several template template parameter bugs
- To: egcs-patches at cygnus dot com
- Subject: PATCH to fix several template template parameter bugs
- From: Kriang Lerdsuwanakij <lerdsuwa at scf-fs dot usc dot edu>
- Date: Mon, 29 Jun 1998 23:31:12 -0700 (PDT)
Hi
This patch fixes several bugs inside the function coerce_template_parms.
The ugly recursion in this function is also removed by introducing a new
function.
Here is the list of bugs fixed by the patch:
- Choosing the right template function from the set of overloading
functions (testcases ttp47.C, ttp48.C).
- Non-type parameters of template template parameters are checked
(ttp49.C).
- Parameters of template template parameters that depend on
preceding parameters (ttp50.C).
- Don't always accessing ARGLIST (TREE_VEC or TREE_LIST) as TREE_LIST
(ttp51.C). [Reported by Martin and again by Haakon in
http://www.cygnus.com/ml/egcs-bugs/1998-Jun/0370.html]
- Don't call tsubst for default arguments when coercing parameters
of template template parameters (ttp51.C).
- Don't be too generous about accepting TYPE_DECL for template
template parameters (ttp52.C). [Exposed in Haakon's testcase.]
--Kriang
* pt.c (coerce_template_template_parms): New function equivalent
to coerce_template_parms when IS_TMPL_PARM is true.
(coerce_template_parms): Use it. Remove the IS_TMPL_PARM parameter,
all callers changed.
(coerce_template_parms): Access ARGLIST properly when creating a
new vector. Only accept implicit TYPE_DECL as valid argument for
a template template parameter when it is a base class of
current_class_type. Don't display error message when COMPLAIN is
false.
diff -crpN gcc-old/cp/pt.c gcc/cp/pt.c
*** gcc-old/cp/pt.c Sat Jun 27 23:52:28 1998
--- gcc/cp/pt.c Sat Jun 27 23:51:50 1998
*************** static char *mangle_class_name_for_templ
*** 84,90 ****
static tree tsubst_expr_values PROTO((tree, tree));
static int list_eq PROTO((tree, tree));
static tree get_class_bindings PROTO((tree, tree, tree, tree));
! static tree coerce_template_parms PROTO((tree, tree, tree, int, int, int));
static tree tsubst_enum PROTO((tree, tree, tree *));
static tree add_to_template_args PROTO((tree, tree));
static void maybe_adjust_types_for_deduction PROTO((unification_kind_t, tree*,
--- 84,90 ----
static tree tsubst_expr_values PROTO((tree, tree));
static int list_eq PROTO((tree, tree));
static tree get_class_bindings PROTO((tree, tree, tree, tree));
! static tree coerce_template_parms PROTO((tree, tree, tree, int, int));
static tree tsubst_enum PROTO((tree, tree, tree *));
static tree add_to_template_args PROTO((tree, tree));
static void maybe_adjust_types_for_deduction PROTO((unification_kind_t, tree*,
*************** convert_nontype_argument (type, expr)
*** 2337,2342 ****
--- 2337,2418 ----
return error_mark_node;
}
+ /* Return 1 if PARM_PARMS and ARG_PARMS matches using rule for
+ template template parameters. Both PARM_PARMS and ARG_PARMS are
+ vectors of TREE_LIST nodes containing TYPE_DECL, TEMPLATE_DECL
+ or PARM_DECL.
+
+ ARG_PARMS may contain more parameters than PARM_PARMS. If this is
+ the case, then extra parameters must have default arguments.
+
+ Consider the example:
+ template <class T, class Allocator = allocator> class vector;
+ template<template <class U> class TT> class C;
+
+ C<vector> is a valid instantiation. PARM_PARMS for the above code
+ contains a TYPE_DECL (for U), ARG_PARMS contains two TYPE_DECLs (for
+ T and Allocator) and OUTER_ARGS contains the argument that is used to
+ substitute the TT parameter. */
+
+ static int
+ coerce_template_template_parms (parm_parms, arg_parms, in_decl, outer_args)
+ tree parm_parms, arg_parms, in_decl, outer_args;
+ {
+ int nparms, nargs, i;
+ tree parm, arg;
+
+ my_friendly_assert (TREE_CODE (parm_parms) == TREE_VEC, 0);
+ my_friendly_assert (TREE_CODE (arg_parms) == TREE_VEC, 0);
+
+ nparms = TREE_VEC_LENGTH (parm_parms);
+ nargs = TREE_VEC_LENGTH (arg_parms);
+
+ /* The rule here is opposite of coerce_template_parms. */
+ if (nargs < nparms
+ || (nargs > nparms
+ && TREE_PURPOSE (TREE_VEC_ELT (arg_parms, nparms)) == NULL_TREE))
+ return 0;
+
+ for (i = 0; i < nparms; ++i)
+ {
+ parm = TREE_VALUE (TREE_VEC_ELT (parm_parms, i));
+ arg = TREE_VALUE (TREE_VEC_ELT (arg_parms, i));
+
+ if (arg == NULL_TREE || arg == error_mark_node
+ || parm == NULL_TREE || parm == error_mark_node)
+ return 0;
+
+ if (TREE_CODE (arg) != TREE_CODE (parm))
+ return 0;
+
+ switch (TREE_CODE (parm))
+ {
+ case TYPE_DECL:
+ break;
+
+ case TEMPLATE_DECL:
+ /* We encounter instantiations of templates like
+ template <template <template <class> class> class TT>
+ class C; */
+ cp_error ("nested template template parameter not implemented");
+ return 0;
+
+ case PARM_DECL:
+ /* The tsubst call is used to handle cases such as
+ template <class T, template <T> class TT> class D;
+ i.e. the parameter list of TT depends on earlier parameters. */
+ if (!comptypes (tsubst (TREE_TYPE (parm), outer_args, in_decl),
+ TREE_TYPE (arg), 1))
+ return 0;
+ break;
+
+ default:
+ my_friendly_abort (0);
+ }
+ }
+ return 1;
+ }
+
/* Convert all template arguments to their appropriate types, and return
a vector containing the resulting values. If any error occurs, return
error_mark_node, and, if COMPLAIN is non-zero, issue an error message.
*************** convert_nontype_argument (type, expr)
*** 2346,2367 ****
If REQUIRE_ALL_ARGUMENTS is non-zero, all arguments must be
provided in ARGLIST, or else trailing parameters must have default
values. If REQUIRE_ALL_ARGUMENTS is zero, we will attempt argument
! deduction for any unspecified trailing arguments.
- If IS_TMPL_PARM is non-zero, we will coercing parameters of template
- template arguments. In this case, ARGLIST is a chain of TREE_LIST
- nodes containing TYPE_DECL, TEMPLATE_DECL or PARM_DECL. */
-
static tree
coerce_template_parms (parms, arglist, in_decl,
complain,
! require_all_arguments,
! is_tmpl_parm)
tree parms, arglist;
tree in_decl;
int complain;
int require_all_arguments;
- int is_tmpl_parm;
{
int nparms, nargs, i, lost = 0;
tree vec = NULL_TREE;
--- 2422,2437 ----
If REQUIRE_ALL_ARGUMENTS is non-zero, all arguments must be
provided in ARGLIST, or else trailing parameters must have default
values. If REQUIRE_ALL_ARGUMENTS is zero, we will attempt argument
! deduction for any unspecified trailing arguments. */
static tree
coerce_template_parms (parms, arglist, in_decl,
complain,
! require_all_arguments)
tree parms, arglist;
tree in_decl;
int complain;
int require_all_arguments;
{
int nparms, nargs, i, lost = 0;
tree vec = NULL_TREE;
*************** coerce_template_parms (parms, arglist, i
*** 2404,2410 ****
tree arg;
tree parm = TREE_VEC_ELT (parms, i);
! if (arglist)
{
arg = arglist;
arglist = TREE_CHAIN (arglist);
--- 2474,2480 ----
tree arg;
tree parm = TREE_VEC_ELT (parms, i);
! if (arglist && TREE_CODE (arglist) == TREE_LIST)
{
arg = arglist;
arglist = TREE_CHAIN (arglist);
*************** coerce_template_parms (parms, arglist, i
*** 2414,2420 ****
else
arg = TREE_VALUE (arg);
}
! else if (is_tmpl_parm && i < nargs)
{
arg = TREE_VEC_ELT (arglist, i);
if (arg == error_mark_node)
--- 2484,2490 ----
else
arg = TREE_VALUE (arg);
}
! else if (i < nargs)
{
arg = TREE_VEC_ELT (arglist, i);
if (arg == error_mark_node)
*************** coerce_template_parms (parms, arglist, i
*** 2440,2455 ****
tree val = 0;
int is_type, requires_type, is_tmpl_type, requires_tmpl_type;
- if (is_tmpl_parm && i < nargs)
- {
- /* In case we are checking arguments inside a template template
- parameter, ARG that does not come from default argument is
- also a TREE_LIST node. Note that ARG can also be a TREE_LIST
- in other cases such as overloaded functions. */
- if (arg != NULL_TREE && arg != error_mark_node)
- arg = TREE_VALUE (arg);
- }
-
if (arg == NULL_TREE)
/* We're out of arguments. */
{
--- 2510,2515 ----
*************** coerce_template_parms (parms, arglist, i
*** 2491,2506 ****
&& CLASSTYPE_TEMPLATE_INFO (arg)
&& TREE_CODE (TYPE_NAME (arg)) == TYPE_DECL
&& DECL_ARTIFICIAL (TYPE_NAME (arg))
! && requires_tmpl_type);
if (is_tmpl_type && TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM)
arg = TYPE_STUB_DECL (arg);
else if (is_tmpl_type && TREE_CODE (arg) == RECORD_TYPE)
arg = CLASSTYPE_TI_TEMPLATE (arg);
! if (is_tmpl_parm && i < nargs)
! is_type = TREE_CODE (arg) == TYPE_DECL || is_tmpl_type;
! else
! is_type = TREE_CODE_CLASS (TREE_CODE (arg)) == 't' || is_tmpl_type;
if (requires_type && ! is_type && TREE_CODE (arg) == SCOPE_REF
&& TREE_CODE (TREE_OPERAND (arg, 0)) == TEMPLATE_TYPE_PARM)
--- 2551,2565 ----
&& CLASSTYPE_TEMPLATE_INFO (arg)
&& TREE_CODE (TYPE_NAME (arg)) == TYPE_DECL
&& DECL_ARTIFICIAL (TYPE_NAME (arg))
! && requires_tmpl_type
! && current_class_type
! && get_binfo (arg, current_class_type, 0));
if (is_tmpl_type && TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM)
arg = TYPE_STUB_DECL (arg);
else if (is_tmpl_type && TREE_CODE (arg) == RECORD_TYPE)
arg = CLASSTYPE_TI_TEMPLATE (arg);
! is_type = TREE_CODE_CLASS (TREE_CODE (arg)) == 't' || is_tmpl_type;
if (requires_type && ! is_type && TREE_CODE (arg) == SCOPE_REF
&& TREE_CODE (TREE_OPERAND (arg, 0)) == TEMPLATE_TYPE_PARM)
*************** coerce_template_parms (parms, arglist, i
*** 2536,2562 ****
{
if (in_decl)
{
! cp_error ("type/value mismatch at argument %d in template parameter list for `%D'",
! i + 1, in_decl);
! if (is_tmpl_type)
! cp_error (" expected a type, got `%T'", DECL_NAME (arg));
! else
! cp_error (" expected a class template, got `%T'", arg);
}
lost++;
TREE_VEC_ELT (vec, i) = error_mark_node;
continue;
}
- if (is_tmpl_parm)
- {
- if (requires_tmpl_type)
- {
- cp_error ("nested template template parameter not implemented");
- lost++;
- TREE_VEC_ELT (vec, i) = error_mark_node;
- }
- continue;
- }
if (is_type)
{
--- 2595,2614 ----
{
if (in_decl)
{
! if (complain)
! {
! cp_error ("type/value mismatch at argument %d in template parameter list for `%D'",
! i + 1, in_decl);
! if (is_tmpl_type)
! cp_error (" expected a type, got `%T'", DECL_NAME (arg));
! else
! cp_error (" expected a class template, got `%T'", arg);
! }
}
lost++;
TREE_VEC_ELT (vec, i) = error_mark_node;
continue;
}
if (is_type)
{
*************** coerce_template_parms (parms, arglist, i
*** 2565,2587 ****
tree parmparm = DECL_INNERMOST_TEMPLATE_PARMS (parm);
tree argparm = DECL_INNERMOST_TEMPLATE_PARMS (arg);
! /* The parameter and argument roles have to be switched
! here in order to handle default arguments properly.
! For example,
! template<template <class> class TT> void f(TT<int>)
! should be able to accept vector<int> which comes from
! template <class T, class Allcator = allocator>
! class vector. */
! val = coerce_template_parms (argparm, parmparm, in_decl, 1, 1, 1);
! if (val != error_mark_node)
! val = arg;
!
! /* TEMPLATE_TEMPLATE_PARM node is preferred over
! TEMPLATE_DECL. */
! if (val != error_mark_node
! && DECL_TEMPLATE_TEMPLATE_PARM_P (val))
! val = TREE_TYPE (val);
}
else
{
--- 2617,2644 ----
tree parmparm = DECL_INNERMOST_TEMPLATE_PARMS (parm);
tree argparm = DECL_INNERMOST_TEMPLATE_PARMS (arg);
! if (coerce_template_template_parms (parmparm, argparm,
! in_decl, vec))
! {
! val = arg;
! /* TEMPLATE_TEMPLATE_PARM node is preferred over
! TEMPLATE_DECL. */
! if (val != error_mark_node
! && DECL_TEMPLATE_TEMPLATE_PARM_P (val))
! val = TREE_TYPE (val);
! }
! else
! {
! if (in_decl && complain)
! {
! cp_error ("type/value mismatch at argument %d in template parameter list for `%D'",
! i + 1, in_decl);
! cp_error (" expected a template of type `%D', got `%D'", parm, arg);
! }
!
! val = error_mark_node;
! }
}
else
{
*************** lookup_template_class (d1, arglist, in_d
*** 3002,3008 ****
CLASSTYPE_GOT_SEMICOLON (parm) = 1;
parmlist = DECL_INNERMOST_TEMPLATE_PARMS (template);
! arglist2 = coerce_template_parms (parmlist, arglist, template, 1, 1, 0);
if (arglist2 == error_mark_node)
return error_mark_node;
--- 3059,3065 ----
CLASSTYPE_GOT_SEMICOLON (parm) = 1;
parmlist = DECL_INNERMOST_TEMPLATE_PARMS (template);
! arglist2 = coerce_template_parms (parmlist, arglist, template, 1, 1);
if (arglist2 == error_mark_node)
return error_mark_node;
*************** lookup_template_class (d1, arglist, in_d
*** 3038,3050 ****
TREE_VEC_ELT (new_args, i) =
coerce_template_parms (TREE_VALUE (t),
TREE_VEC_ELT (arglist, i),
! template, 1, 1, 0);
arglist = new_args;
}
else
arglist = coerce_template_parms (parmlist,
innermost_args (arglist, 0),
! template, 1, 1, 0);
if (arglist == error_mark_node)
return error_mark_node;
if (uses_template_parms (arglist))
--- 3095,3107 ----
TREE_VEC_ELT (new_args, i) =
coerce_template_parms (TREE_VALUE (t),
TREE_VEC_ELT (arglist, i),
! template, 1, 1);
arglist = new_args;
}
else
arglist = coerce_template_parms (parmlist,
innermost_args (arglist, 0),
! template, 1, 1);
if (arglist == error_mark_node)
return error_mark_node;
if (uses_template_parms (arglist))
*************** type_unification (tparms, targs, parms,
*** 5831,5837 ****
{
tree arg_vec;
arg_vec = coerce_template_parms (tparms, explicit_targs, NULL_TREE, 0,
! 0, 0);
if (arg_vec == error_mark_node)
return 1;
--- 5888,5894 ----
{
tree arg_vec;
arg_vec = coerce_template_parms (tparms, explicit_targs, NULL_TREE, 0,
! 0);
if (arg_vec == error_mark_node)
return 1;
*************** unify (tparms, targs, parm, arg, strict,
*** 6247,6256 ****
in order to handle default arguments properly. For example,
template<template <class> class TT> void f(TT<int>)
should be able to accept vector<int> which comes from
! template <class T, class Allcator = allocator>
class vector. */
! if (coerce_template_parms (argtmplvec, parmvec, parmtmpl, 1, 1, 0)
== error_mark_node)
return 1;
--- 6304,6313 ----
in order to handle default arguments properly. For example,
template<template <class> class TT> void f(TT<int>)
should be able to accept vector<int> which comes from
! template <class T, class Allocator = allocator>
class vector. */
! if (coerce_template_parms (argtmplvec, parmvec, parmtmpl, 1, 1)
== error_mark_node)
return 1;
diff -crpN gcc-old/testsuite/g++.old-deja/g++.pt/ttp3.C gcc/testsuite/g++.old-deja/g++.pt/ttp3.C
*** gcc-old/testsuite/g++.old-deja/g++.pt/ttp3.C Sat Jun 27 23:54:39 1998
--- gcc/testsuite/g++.old-deja/g++.pt/ttp3.C Sat Jun 27 23:55:00 1998
*************** template<class E,class F> class D
*** 5,11 ****
};
template<template<class> class D,class E> class C
! { // ERROR - ref below
};
int main()
--- 5,11 ----
};
template<template<class> class D,class E> class C
! {
};
int main()
diff -crpN gcc-old/testsuite/g++.old-deja/g++.pt/ttp47.C gcc/testsuite/g++.old-deja/g++.pt/ttp47.C
*** gcc-old/testsuite/g++.old-deja/g++.pt/ttp47.C Wed Dec 31 16:00:00 1969
--- gcc/testsuite/g++.old-deja/g++.pt/ttp47.C Sat Jun 27 23:57:12 1998
***************
*** 0 ****
--- 1,16 ----
+ template <template<class,class> class TT, class T> void f(T)
+ {
+ }
+
+ template <template<class> class TT, class T> void f(T)
+ {
+ }
+
+ template <class T> class C {};
+ template <class T,class U> class D {};
+
+ int main()
+ {
+ f<C>(1);
+ f<D>(1);
+ }
diff -crpN gcc-old/testsuite/g++.old-deja/g++.pt/ttp48.C gcc/testsuite/g++.old-deja/g++.pt/ttp48.C
*** gcc-old/testsuite/g++.old-deja/g++.pt/ttp48.C Wed Dec 31 16:00:00 1969
--- gcc/testsuite/g++.old-deja/g++.pt/ttp48.C Sat Jun 27 23:57:39 1998
***************
*** 0 ****
--- 1,16 ----
+ template <template<int> class TT, class T> void f(T)
+ {
+ }
+
+ template <template<class> class TT, class T> void f(T)
+ {
+ }
+
+ template <class T> class C {};
+ template <int> class D {};
+
+ int main()
+ {
+ f<C>(1);
+ f<D>(1);
+ }
diff -crpN gcc-old/testsuite/g++.old-deja/g++.pt/ttp49.C gcc/testsuite/g++.old-deja/g++.pt/ttp49.C
*** gcc-old/testsuite/g++.old-deja/g++.pt/ttp49.C Wed Dec 31 16:00:00 1969
--- gcc/testsuite/g++.old-deja/g++.pt/ttp49.C Sat Jun 27 23:58:04 1998
***************
*** 0 ****
--- 1,9 ----
+ // Build don't link:
+
+ template <int i> class C {};
+ template <template <long> class TT> class D {};
+
+ int main()
+ {
+ D<C> d; // ERROR - args not match
+ }
diff -crpN gcc-old/testsuite/g++.old-deja/g++.pt/ttp50.C gcc/testsuite/g++.old-deja/g++.pt/ttp50.C
*** gcc-old/testsuite/g++.old-deja/g++.pt/ttp50.C Wed Dec 31 16:00:00 1969
--- gcc/testsuite/g++.old-deja/g++.pt/ttp50.C Sat Jun 27 23:58:48 1998
***************
*** 0 ****
--- 1,7 ----
+ template <class T, template <T> class TT> class C {};
+ template <int> class D {};
+
+ int main()
+ {
+ C<int,D> c;
+ }
diff -crpN gcc-old/testsuite/g++.old-deja/g++.pt/ttp51.C gcc/testsuite/g++.old-deja/g++.pt/ttp51.C
*** gcc-old/testsuite/g++.old-deja/g++.pt/ttp51.C Wed Dec 31 16:00:00 1969
--- gcc/testsuite/g++.old-deja/g++.pt/ttp51.C Sat Jun 27 23:59:06 1998
***************
*** 0 ****
--- 1,13 ----
+ template<class E, int i, class F, class G=int, int j=i, class H=E> class D
+ {
+ };
+
+ template<template<class,int,class,class> class D,class E> class C
+ {
+ D<E,2,char,bool> d;
+ };
+
+ int main()
+ {
+ C<D,int> c;
+ }
diff -crpN gcc-old/testsuite/g++.old-deja/g++.pt/ttp52.C gcc/testsuite/g++.old-deja/g++.pt/ttp52.C
*** gcc-old/testsuite/g++.old-deja/g++.pt/ttp52.C Wed Dec 31 16:00:00 1969
--- gcc/testsuite/g++.old-deja/g++.pt/ttp52.C Sun Jun 28 00:16:58 1998
***************
*** 0 ****
--- 1,18 ----
+ // Build don't link:
+
+ template<class A,class B> class mymap {};
+
+ template<class Key,
+ class Value,
+ template<class, class > class MapT>
+ class base
+ {
+
+ };
+
+ // specialization
+ template<class Key, class Value>
+ class base<Key, Value, mymap<int, int > > // ERROR - mymap<...> is not a template
+ { // ERROR - Bad class name
+
+ };