This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
PATCH for member class templates
- To: Jason Merrill <jason at cygnus dot com>
- Subject: PATCH for member class templates
- From: Mark Mitchell <mmitchell at usa dot net>
- Date: Mon, 4 May 1998 23:07:24 -0700
- Cc: egcs-bugs at cygnus dot com
- Reply-to: mmitchell at usa dot net
Jason --
Here's a patch that improves the handling of member class
templates. For example, we no longer crash, or fail to link, on the
following:
template <class T>
struct S1
{
template <class U>
struct S2
{
S2(U);
void g()
{
S2<U> s2u (u);
}
U& u;
};
template <class U>
void f(U u)
{
S2<U> s2u(u);
s2u.g();
}
};
void g()
{
S1<int> s1;
s1.f(3.0);
}
I've got a huge test case which works succesfully after applying this
patch. Is this OK?
--
Mark Mitchell <mmitchell@usa.net>
http://home.earthlink.net/~mbmitchell
Consulting Services Available
Mon May 4 22:54:12 1998 Mark Mitchell <mmitchell@usa.net>
* method.c (build_overload_identifier): Only use the innermost
template arguments when mangling.
* pt.c (tsubst_template_argument_vector): New function.
(complete_template_args): Deal with the situation where the
extra_args contain more than one level of arguments.
(lookup_template_class): Deal with member template classes, which
may have more than one level of arguments.
(tsubst): Don't tsbust into the TREE_TYPE of an IDENTIFIER_NODE.
Improve handling of member template classes. Use
DECL_PRIMARY_TEMPLATE instead of inline expansion. Use
tsubst_template_argument_vector where appropriate.
(regenerate_decl_from_template): Break out from ...
(instantiate_decl): Here.
Index: cp/method.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/method.c,v
retrieving revision 1.43
diff -c -p -r1.43 method.c
*** method.c 1998/04/17 08:32:50 1.43
--- method.c 1998/05/05 05:42:32
*************** build_overload_identifier (name)
*** 894,900 ****
{
tree template, parmlist, arglist, tname;
template = CLASSTYPE_TEMPLATE_INFO (TREE_TYPE (name));
! arglist = TREE_VALUE (template);
template = TREE_PURPOSE (template);
tname = DECL_NAME (template);
parmlist = DECL_INNERMOST_TEMPLATE_PARMS (template);
--- 894,900 ----
{
tree template, parmlist, arglist, tname;
template = CLASSTYPE_TEMPLATE_INFO (TREE_TYPE (name));
! arglist = innermost_args (TREE_VALUE (template), 0);
template = TREE_PURPOSE (template);
tname = DECL_NAME (template);
parmlist = DECL_INNERMOST_TEMPLATE_PARMS (template);
Index: cp/pt.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/pt.c,v
retrieving revision 1.124
diff -c -p -r1.124 pt.c
*** pt.c 1998/04/26 16:30:10 1.124
--- pt.c 1998/05/05 05:42:53
*************** static tree tsubst_friend_class PROTO((t
*** 103,108 ****
--- 110,117 ----
static tree get_bindings_real PROTO((tree, tree, tree, int));
static int template_decl_level PROTO((tree));
static tree maybe_get_template_decl_from_type_decl PROTO((tree));
+ static tree tsubst_template_arg_vector PROTO((tree, tree));
+ static void regenerate_decl_from_template PROTO((tree, tree));
/* Do any processing required when DECL (a member template declaration
using TEMPLATE_PARAMETERS as its innermost parameter list) is
*************** is_member_template (t)
*** 357,363 ****
}
/* Return a new template argument vector which contains all of ARGS
! for all outer templates TYPE is contained in, but has as its
innermost set of arguments the EXTRA_ARGS. If UNBOUND_ONLY, we
are only interested in unbound template arguments, not arguments from
enclosing templates that have been instantiated already. */
--- 367,373 ----
}
/* Return a new template argument vector which contains all of ARGS
! for all outer templates TMPL is contained in, but has as its
innermost set of arguments the EXTRA_ARGS. If UNBOUND_ONLY, we
are only interested in unbound template arguments, not arguments from
enclosing templates that have been instantiated already. */
*************** complete_template_args (tmpl, extra_args
*** 370,379 ****
/* depth is the number of levels of enclosing args we're adding. */
int depth, i;
tree args, new_args, spec_args = NULL_TREE;
!
my_friendly_assert (TREE_CODE (tmpl) == TEMPLATE_DECL, 0);
my_friendly_assert (TREE_CODE (extra_args) == TREE_VEC, 0);
if (DECL_TEMPLATE_INFO (tmpl) && !unbound_only)
{
/* A specialization of a member template of a template class shows up
--- 380,395 ----
/* depth is the number of levels of enclosing args we're adding. */
int depth, i;
tree args, new_args, spec_args = NULL_TREE;
! int extra_arg_depth;
!
my_friendly_assert (TREE_CODE (tmpl) == TEMPLATE_DECL, 0);
my_friendly_assert (TREE_CODE (extra_args) == TREE_VEC, 0);
+ if (TREE_CODE (TREE_VEC_ELT (extra_args, 0)) == TREE_VEC)
+ extra_arg_depth = TREE_VEC_LENGTH (extra_args);
+ else
+ extra_arg_depth = 1;
+
if (DECL_TEMPLATE_INFO (tmpl) && !unbound_only)
{
/* A specialization of a member template of a template class shows up
*************** complete_template_args (tmpl, extra_args
*** 402,408 ****
template args. */
depth = 0;
! new_args = make_tree_vec (depth + 1 + (!!spec_args));
if (depth == 1)
TREE_VEC_ELT (new_args, 0) = args;
--- 418,424 ----
template args. */
depth = 0;
! new_args = make_tree_vec (depth + extra_arg_depth + (!!spec_args));
if (depth == 1)
TREE_VEC_ELT (new_args, 0) = args;
*************** complete_template_args (tmpl, extra_args
*** 424,430 ****
if (depth == 0)
return extra_args;
! new_args = make_tree_vec (depth + 1);
/* If this isn't a member template, extra_args is for the innermost
template class, so skip over it. */
--- 440,446 ----
if (depth == 0)
return extra_args;
! new_args = make_tree_vec (depth + extra_arg_depth);
/* If this isn't a member template, extra_args is for the innermost
template class, so skip over it. */
*************** complete_template_args (tmpl, extra_args
*** 444,453 ****
}
}
! TREE_VEC_ELT (new_args, depth) = extra_args;
if (spec_args)
! TREE_VEC_ELT (new_args, depth + 1) = spec_args;
return new_args;
}
--- 460,473 ----
}
}
! if (extra_arg_depth == 1)
! TREE_VEC_ELT (new_args, depth++) = extra_args;
! else
! for (i = 0; i < extra_arg_depth; ++i)
! TREE_VEC_ELT (new_args, depth++) = TREE_VEC_ELT (extra_args, i);
if (spec_args)
! TREE_VEC_ELT (new_args, depth) = spec_args;
return new_args;
}
*************** push_template_decl_real (decl, is_friend
*** 1807,1814 ****
cp_error (" but `%#T' has %d", ctx, TREE_VEC_LENGTH (t));
}
}
! /* Get the innermost set of template arguments. */
! args = innermost_args (args, 0);
DECL_TEMPLATE_RESULT (tmpl) = decl;
TREE_TYPE (tmpl) = TREE_TYPE (decl);
--- 1827,1841 ----
cp_error (" but `%#T' has %d", ctx, TREE_VEC_LENGTH (t));
}
}
! /* Get the innermost set of template arguments. We don't do this
! for a non-template member function of a nested template class
! because there we will never get a `partial instantiation' of the
! function containing the outer arguments, and so we must save all
! of the arguments here. */
! if (TREE_CODE (decl) != FUNCTION_DECL
! || template_class_depth (ctx) <= 1
! || primary)
! args = innermost_args (args, 0);
DECL_TEMPLATE_RESULT (tmpl) = decl;
TREE_TYPE (tmpl) = TREE_TYPE (decl);
*************** lookup_template_class (d1, arglist, in_d
*** 2865,2875 ****
|| (TREE_CODE (TYPE_CONTEXT (TREE_TYPE (template)))
== FUNCTION_DECL))
{
parmlist = DECL_INNERMOST_TEMPLATE_PARMS (template);
! arglist = coerce_template_parms (parmlist, arglist, template,
! 1, 1, 0);
! if (arglist == error_mark_node)
return error_mark_node;
if (uses_template_parms (arglist))
{
--- 2892,2927 ----
|| (TREE_CODE (TYPE_CONTEXT (TREE_TYPE (template)))
== FUNCTION_DECL))
{
+ tree arglist_for_mangling;
+
parmlist = DECL_INNERMOST_TEMPLATE_PARMS (template);
! if (/* ARGLIST can be NULL_TREE if there are default arguments. */
! arglist != NULL_TREE
! && TREE_CODE (arglist) == TREE_VEC
! && TREE_VEC_LENGTH (arglist) > 1
! && list_length (DECL_TEMPLATE_PARMS (template)) > 1)
! {
! /* We have multiple levels of arguments to coerce, at once. */
! tree new_args =
! make_tree_vec (list_length (DECL_TEMPLATE_PARMS (template)));
! int i;
!
! for (i = TREE_VEC_LENGTH (arglist) - 1,
! t = DECL_TEMPLATE_PARMS (template);
! i >= 0 && t != NULL_TREE;
! --i, t = TREE_CHAIN (t))
! 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))
{
*************** lookup_template_class (d1, arglist, in_d
*** 2898,2907 ****
}
}
/* FIXME avoid duplication. */
mangled_name = mangle_class_name_for_template (IDENTIFIER_POINTER (d1),
parmlist,
! arglist,
context);
id = get_identifier (mangled_name);
IDENTIFIER_TEMPLATE (id) = d1;
--- 2950,2964 ----
}
}
+ if (TREE_CODE (arglist) == TREE_VEC)
+ arglist_for_mangling = innermost_args (arglist, 0);
+ else
+ arglist_for_mangling = arglist;
+
/* FIXME avoid duplication. */
mangled_name = mangle_class_name_for_template (IDENTIFIER_POINTER (d1),
parmlist,
! arglist_for_mangling,
context);
id = get_identifier (mangled_name);
IDENTIFIER_TEMPLATE (id) = d1;
*************** innermost_args (args, is_spec)
*** 3829,3839 ****
tree args;
int is_spec;
{
! if (TREE_CODE (TREE_VEC_ELT (args, 0)) == TREE_VEC)
return TREE_VEC_ELT (args, TREE_VEC_LENGTH (args) - 1 - is_spec);
return args;
}
/* Take the tree structure T and replace template parameters used therein
with the argument vector ARGS. IN_DECL is an associated decl for
diagnostics.
--- 3886,3931 ----
tree args;
int is_spec;
{
! if (args != NULL_TREE && TREE_CODE (TREE_VEC_ELT (args, 0)) == TREE_VEC)
return TREE_VEC_ELT (args, TREE_VEC_LENGTH (args) - 1 - is_spec);
return args;
}
+ /* Substitute ARGS into the vector of template arguments T. */
+
+ tree
+ tsubst_template_arg_vector (t, args)
+ tree t;
+ tree args;
+ {
+ int len = TREE_VEC_LENGTH (t), need_new = 0, i;
+ tree *elts = (tree *) alloca (len * sizeof (tree));
+
+ bzero ((char *) elts, len * sizeof (tree));
+
+ for (i = 0; i < len; i++)
+ {
+ if (TREE_VEC_ELT (t, i) != NULL_TREE
+ && TREE_CODE (TREE_VEC_ELT (t, i)) == TREE_VEC)
+ elts[i] = tsubst_template_arg_vector (TREE_VEC_ELT (t, i), args);
+ else
+ elts[i] = maybe_fold_nontype_arg
+ (tsubst_expr (TREE_VEC_ELT (t, i), args, NULL_TREE));
+
+ if (elts[i] != TREE_VEC_ELT (t, i))
+ need_new = 1;
+ }
+
+ if (!need_new)
+ return t;
+
+ t = make_tree_vec (len);
+ for (i = 0; i < len; i++)
+ TREE_VEC_ELT (t, i) = elts[i];
+
+ return t;
+ }
+
/* 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 (t, args, in_decl)
*** 3857,3863 ****
--- 3949,3957 ----
type = TREE_TYPE (t);
if (type == unknown_type_node)
my_friendly_abort (42);
+
if (type && TREE_CODE (t) != FUNCTION_DECL
+ && TREE_CODE (t) != IDENTIFIER_NODE
&& TREE_CODE (t) != TYPENAME_TYPE
&& TREE_CODE (t) != TEMPLATE_DECL)
type = tsubst (type, args, in_decl);
*************** tsubst (t, args, in_decl)
*** 3881,3894 ****
tree context;
tree r;
! context =
! TYPE_CONTEXT (t)
! ? tsubst (TYPE_CONTEXT (t), args, in_decl) : NULL_TREE;
r = lookup_template_class (t, argvec, in_decl, context);
return cp_build_type_variant (r, TYPE_READONLY (t),
! TYPE_VOLATILE (t));
}
/* else fall through */
--- 3975,4006 ----
tree context;
tree r;
! if (TYPE_CONTEXT (t) != NULL_TREE)
! {
! context = tsubst (TYPE_CONTEXT (t), args, in_decl);
!
! if (TREE_CODE (context) != FUNCTION_DECL)
! {
! /* For a member class template, we need all the
! template arguments. */
! if (CLASSTYPE_IS_TEMPLATE (TYPE_CONTEXT (t)))
! argvec =
! add_to_template_args (CLASSTYPE_TI_ARGS (context),
! argvec);
!
! if (CLASSTYPE_TEMPLATE_INFO (context))
! argvec =
! complete_template_args (CLASSTYPE_TI_TEMPLATE (context),
! argvec, 0);
! }
! }
! else
! context = NULL_TREE;
r = lookup_template_class (t, argvec, in_decl, context);
return cp_build_type_variant (r, TYPE_READONLY (t),
! TYPE_VOLATILE (t));
}
/* else fall through */
*************** tsubst (t, args, in_decl)
*** 4157,4163 ****
}
if (PRIMARY_TEMPLATE_P (t))
! TREE_TYPE (DECL_INNERMOST_TEMPLATE_PARMS (tmpl)) = tmpl;
/* We don't partially instantiate partial specializations. */
if (TREE_CODE (decl) == TYPE_DECL)
--- 4269,4275 ----
}
if (PRIMARY_TEMPLATE_P (t))
! DECL_PRIMARY_TEMPLATE (tmpl) = tmpl;
/* We don't partially instantiate partial specializations. */
if (TREE_CODE (decl) == TYPE_DECL)
*************** tsubst (t, args, in_decl)
*** 4596,4625 ****
}
/* Otherwise, a vector of template arguments. */
! {
! int len = TREE_VEC_LENGTH (t), need_new = 0, i;
! tree *elts = (tree *) alloca (len * sizeof (tree));
!
! bzero ((char *) elts, len * sizeof (tree));
!
! for (i = 0; i < len; i++)
! {
! elts[i] = maybe_fold_nontype_arg
! (tsubst_expr (TREE_VEC_ELT (t, i), args, in_decl));
!
! if (elts[i] != TREE_VEC_ELT (t, i))
! need_new = 1;
! }
- if (!need_new)
- return t;
-
- t = make_tree_vec (len);
- for (i = 0; i < len; i++)
- TREE_VEC_ELT (t, i) = elts[i];
-
- return t;
- }
case POINTER_TYPE:
case REFERENCE_TYPE:
{
--- 4708,4715 ----
}
/* Otherwise, a vector of template arguments. */
! return tsubst_template_arg_vector (t, args);
case POINTER_TYPE:
case REFERENCE_TYPE:
{
*************** do_type_instantiation (t, storage)
*** 6579,6584 ****
--- 6834,6908 ----
}
}
+ /* Given a function DECL, which is a specialization of TEMP, modify
+ DECL to be a re-instantiation of TEMPL with the same template
+ arguments.
+
+ One reason for doing this is a scenario like this:
+
+ template <class T>
+ void f(const T&, int i);
+
+ void g() { f(3, 7); }
+
+ template <class T>
+ void f(const T& t, const int i) { }
+
+ Note that when the template is first instantiated, with
+ instantiate_template, the resulting DECL will have no name for the
+ first parameter, and the wrong type for the second. So, when we go
+ to instantiate the DECL, we regenerate it. */
+
+ void
+ regenerate_decl_from_template (decl, tmpl)
+ tree decl;
+ tree tmpl;
+ {
+ tree args;
+ tree save_ti;
+ tree code_pattern;
+ tree new_decl;
+
+ args = DECL_TI_ARGS (decl);
+ code_pattern = DECL_TEMPLATE_RESULT (tmpl);
+
+ /* Trick tsubst into giving us a new decl. CODE_PATTERN must be the
+ most distant ancestor of DECL, since that's the one that will
+ actually be altered by a redefinition. */
+ save_ti = DECL_TEMPLATE_INFO (code_pattern);
+ DECL_TEMPLATE_INFO (code_pattern) = NULL_TREE;
+ new_decl = tsubst (code_pattern, args, NULL_TREE);
+ SET_DECL_IMPLICIT_INSTANTIATION (new_decl);
+ DECL_TEMPLATE_INFO (code_pattern) = save_ti;
+
+ if (TREE_CODE (decl) == VAR_DECL)
+ {
+ /* Set up DECL_INITIAL, since tsubst doesn't. */
+ pushclass (DECL_CONTEXT (decl), 2);
+ DECL_INITIAL (new_decl) =
+ tsubst_expr (DECL_INITIAL (code_pattern), args,
+ DECL_TI_TEMPLATE (decl));
+ popclass (1);
+ }
+
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ {
+ /* Convince duplicate_decls to use the DECL_ARGUMENTS from the
+ new decl. */
+ DECL_INITIAL (new_decl) = error_mark_node;
+
+ if (DECL_TEMPLATE_SPECIALIZATION (new_decl)
+ && !DECL_TEMPLATE_INFO (new_decl))
+ /* Set up the information about what is being specialized. */
+ DECL_TEMPLATE_INFO (new_decl) = DECL_TEMPLATE_INFO (decl);
+ }
+
+ duplicate_decls (new_decl, decl);
+
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ DECL_INITIAL (new_decl) = NULL_TREE;
+ }
+
/* Produce the definition of D, a _DECL generated from a template. */
tree
*************** instantiate_decl (d)
*** 6588,6594 ****
tree ti = DECL_TEMPLATE_INFO (d);
tree tmpl = TI_TEMPLATE (ti);
tree args = TI_ARGS (ti);
! tree td, temp;
tree decl_pattern, code_pattern;
tree save_ti;
int nested = in_function_p ();
--- 6912,6918 ----
tree ti = DECL_TEMPLATE_INFO (d);
tree tmpl = TI_TEMPLATE (ti);
tree args = TI_ARGS (ti);
! tree td;
tree decl_pattern, code_pattern;
tree save_ti;
int nested = in_function_p ();
*************** instantiate_decl (d)
*** 6697,6735 ****
lineno = DECL_SOURCE_LINE (d);
input_filename = DECL_SOURCE_FILE (d);
-
- /* Trick tsubst into giving us a new decl in case the template changed. */
- save_ti = DECL_TEMPLATE_INFO (decl_pattern);
- DECL_TEMPLATE_INFO (decl_pattern) = NULL_TREE;
- /* decl_pattern has all but one level of template parms bound. Only pass
- in that one level of args. */
- temp = innermost_args (args, DECL_TEMPLATE_SPECIALIZATION (decl_pattern));
- td = tsubst (decl_pattern, temp, tmpl);
- SET_DECL_IMPLICIT_INSTANTIATION (td);
- DECL_TEMPLATE_INFO (decl_pattern) = save_ti;
! /* And set up DECL_INITIAL, since tsubst doesn't. */
! if (TREE_CODE (td) == VAR_DECL)
! {
! pushclass (DECL_CONTEXT (d), 2);
! DECL_INITIAL (td) = tsubst_expr (DECL_INITIAL (code_pattern), args,
! tmpl);
! popclass (1);
! }
!
! if (TREE_CODE (d) == FUNCTION_DECL)
! {
! /* Convince duplicate_decls to use the DECL_ARGUMENTS from the
! new decl. */
! DECL_INITIAL (td) = error_mark_node;
!
! if (DECL_TEMPLATE_SPECIALIZATION (td) && !DECL_TEMPLATE_INFO (td))
! /* Set up the information about what is being specialized. */
! DECL_TEMPLATE_INFO (td) = DECL_TEMPLATE_INFO (d);
! }
! duplicate_decls (td, d);
! if (TREE_CODE (d) == FUNCTION_DECL)
! DECL_INITIAL (td) = 0;
if (TREE_CODE (d) == VAR_DECL)
{
--- 7021,7028 ----
lineno = DECL_SOURCE_LINE (d);
input_filename = DECL_SOURCE_FILE (d);
! regenerate_decl_from_template (d, td);
if (TREE_CODE (d) == VAR_DECL)
{
Index: testsuite/g++.old-deja/g++.pt/memclass9.C
===================================================================
RCS file: memclass9.C
diff -N memclass9.C
*** /dev/null Mon Dec 31 20:00:00 1979
--- memclass9.C Mon May 4 22:42:53 1998
***************
*** 0 ****
--- 1,30 ----
+ template <class T>
+ struct S1
+ {
+ template <class U>
+ struct S2
+ {
+ S2(U);
+
+ void g()
+ {
+ S2<U> s2u (u);
+ }
+
+ U& u;
+ };
+
+ template <class U>
+ void f(U u)
+ {
+ S2<U> s2u(u);
+ s2u.g();
+ }
+ };
+
+ void g()
+ {
+ S1<int> s1;
+ s1.f(3.0);
+ }
+