This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
PATCH for nember class template crash
- To: egcs-patches at cygnus dot com
- Subject: PATCH for nember class template crash
- From: Mark Mitchell <mark at markmitchell dot com>
- Date: Tue, 4 Aug 1998 11:41:30 -0700
- Cc: Jason Merrill <jason at cygnus dot com>
- Reply-to: mark at markmitchell dot com
Here's a patch for:
+ // Build don't link:
+
+ template <class Q>
+ class A {
+ public:
+
+ typedef enum { X, Y } B;
+ template <B c> class Traits{ };
+ };
+
+
+ template class A<int>;
+ template class A<double>::Traits<A<double>::X>;
--
Mark Mitchell mark@markmitchell.com
Mark Mitchell Consulting http://www.markmitchell.com
1998-08-04 Mark Mitchell <mark@markmitchell.com>
* decl.c (pushtag): Don't mangle the name of a TYPE_DECL if it
uses template parameters.
* init.c (build_offset_ref): Deal with a TEMPLATE_ID_EXPR whose
name is a LOOKUP_EXPR, rather than an IDENTIFIER_NODE.
* method.c (build_template_parm_names): Use the full set of
template arguments for tsubst'ing.
(build_overload_identifier): Pass the full set of template
arguments to build_template_parm_names, not just the
innermost_args.
* pt.c (TMPL_ARGS_DEPTH): Define using
TMPL_ARGS_HAVE_MULTIPLE_LEVELS, for clarity.
(NUM_TMPL_ARGS): New macro.
(add_outermost_template_args): Deal with the case where the outer
args will be completely discarded.
(coerce_template_parms): Use the full set of template arguments
for tsubst'ing. Simplify. Add some asserts. Improve
error messages.
(lookup_template_class): Pass the full set of template arguments
to coerce_template_parms.
(tsubst): Add assertion.
(do_type_instantiation): Don't instantiate member template
classes.
Index: testsuite/g++.old-deja/g++.pt/memclass16.C
===================================================================
RCS file: memclass16.C
diff -N memclass16.C
*** /dev/null Mon Dec 31 20:00:00 1979
--- memclass16.C Tue Aug 4 11:23:07 1998
***************
*** 0 ****
--- 1,13 ----
+ // Build don't link:
+
+ template <class Q>
+ class A {
+ public:
+
+ typedef enum { X, Y } B;
+ template <B c> class Traits{ };
+ };
+
+
+ template class A<int>;
+ template class A<double>::Traits<A<double>::X>;
Index: cp/decl.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/decl.c,v
retrieving revision 1.173
diff -c -p -r1.173 decl.c
*** decl.c 1998/07/31 15:01:14 1.173
--- decl.c 1998/08/04 18:23:49
*************** pushtag (name, type, globalize)
*** 2396,2403 ****
TYPE_CONTEXT (type) = DECL_CONTEXT (d);
DECL_ASSEMBLER_NAME (d) = DECL_NAME (d);
! DECL_ASSEMBLER_NAME (d)
! = get_identifier (build_overload_name (type, 1, 1));
}
}
if (b->parm_flag == 2)
--- 2396,2404 ----
TYPE_CONTEXT (type) = DECL_CONTEXT (d);
DECL_ASSEMBLER_NAME (d) = DECL_NAME (d);
! if (!uses_template_parms (type))
! DECL_ASSEMBLER_NAME (d)
! = get_identifier (build_overload_name (type, 1, 1));
}
}
if (b->parm_flag == 2)
Index: cp/method.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/method.c,v
retrieving revision 1.67
diff -c -p -r1.67 method.c
*** method.c 1998/08/02 21:37:19 1.67
--- method.c 1998/08/04 18:24:16
*************** build_template_parm_names (parmlist, arg
*** 862,874 ****
tree arglist;
{
int i, nparms;
!
nparms = TREE_VEC_LENGTH (parmlist);
icat (nparms);
for (i = 0; i < nparms; i++)
{
tree parm = TREE_VALUE (TREE_VEC_ELT (parmlist, i));
! tree arg = TREE_VEC_ELT (arglist, i);
if (TREE_CODE (parm) == TYPE_DECL)
{
/* This parameter is a type. */
--- 862,875 ----
tree arglist;
{
int i, nparms;
! tree inner_args = innermost_args (arglist);
!
nparms = TREE_VEC_LENGTH (parmlist);
icat (nparms);
for (i = 0; i < nparms; i++)
{
tree parm = TREE_VALUE (TREE_VEC_ELT (parmlist, i));
! tree arg = TREE_VEC_ELT (inner_args, i);
if (TREE_CODE (parm) == TYPE_DECL)
{
/* This parameter is a type. */
*************** build_overload_identifier (name)
*** 919,927 ****
{
/* NAME is the TYPE_DECL for a template specialization. */
tree template, parmlist, arglist, tname;
! template = CLASSTYPE_TEMPLATE_INFO (TREE_TYPE (name));
! arglist = innermost_args (TREE_VALUE (template));
! template = TREE_PURPOSE (template);
tname = DECL_NAME (template);
parmlist = DECL_INNERMOST_TEMPLATE_PARMS (template);
OB_PUTC ('t');
--- 920,927 ----
{
/* NAME is the TYPE_DECL for a template specialization. */
tree template, parmlist, arglist, tname;
! template = CLASSTYPE_TI_TEMPLATE (TREE_TYPE (name));
! arglist = CLASSTYPE_TI_ARGS (TREE_TYPE (name));
tname = DECL_NAME (template);
parmlist = DECL_INNERMOST_TEMPLATE_PARMS (template);
OB_PUTC ('t');
Index: cp/pt.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/pt.c,v
retrieving revision 1.172
diff -c -p -r1.172 pt.c
*** pt.c 1998/08/02 21:37:20 1.172
--- pt.c 1998/08/04 18:25:11
*************** static int template_class_depth_real PRO
*** 135,153 ****
only one level of arguments, but which is a TREE_VEC containing as
its only entry the TREE_VEC for that level. */
- /* The depth of a template argument vector. When called directly by
- the parser, we use a TREE_LIST rather than a TREE_VEC to represent
- template arguments. In fact, we may even see NULL_TREE if there
- are no template arguments. In both of those cases, there is only
- one level of template arguments. */
- #define TMPL_ARGS_DEPTH(NODE) \
- ((NODE != NULL_TREE \
- && TREE_CODE (NODE) == TREE_VEC \
- && TREE_VEC_LENGTH (NODE) > 0 \
- && TREE_VEC_ELT (NODE, 0) != NULL_TREE \
- && TREE_CODE (TREE_VEC_ELT (NODE, 0)) == TREE_VEC) ? \
- TREE_VEC_LENGTH (NODE) : 1)
-
/* Non-zero if the template arguments is actually a vector of vectors,
rather than just a vector. */
#define TMPL_ARGS_HAVE_MULTIPLE_LEVELS(NODE) \
--- 135,140 ----
*************** static int template_class_depth_real PRO
*** 157,162 ****
--- 144,157 ----
&& TREE_VEC_ELT (NODE, 0) != NULL_TREE \
&& TREE_CODE (TREE_VEC_ELT (NODE, 0)) == TREE_VEC)
+ /* The depth of a template argument vector. When called directly by
+ the parser, we use a TREE_LIST rather than a TREE_VEC to represent
+ template arguments. In fact, we may even see NULL_TREE if there
+ are no template arguments. In both of those cases, there is only
+ one level of template arguments. */
+ #define TMPL_ARGS_DEPTH(NODE) \
+ (TMPL_ARGS_HAVE_MULTIPLE_LEVELS (NODE) ? TREE_VEC_LENGTH (NODE) : 1)
+
/* The LEVELth level of the template ARGS. Note that template
parameter levels are indexed from 1, not from 0. */
#define TMPL_ARGS_LEVEL(ARGS, LEVEL) \
*************** static int template_class_depth_real PRO
*** 177,182 ****
--- 172,184 ----
#define SET_TMPL_ARG(ARGS, LEVEL, IDX, VAL) \
(TREE_VEC_ELT (TREE_VEC_ELT ((ARGS), (LEVEL) - 1), (IDX)) = (VAL))
+ /* Given a single level of template arguments in NODE, return the
+ number of arguments. */
+ #define NUM_TMPL_ARGS(NODE) \
+ ((NODE) == NULL_TREE ? 0 \
+ : (TREE_CODE (NODE) == TREE_VEC \
+ ? TREE_VEC_LENGTH (NODE) : list_length (NODE)))
+
/* The number of levels of template parameters given by NODE. */
#define TMPL_PARMS_DEPTH(NODE) \
(TREE_INT_CST_HIGH (TREE_PURPOSE (NODE)))
*************** add_outermost_template_args (args, extra
*** 506,511 ****
--- 508,523 ----
{
tree new_args;
+ /* If there are more levels of EXTRA_ARGS than there are ARGS,
+ something very fishy is going on. */
+ my_friendly_assert (TMPL_ARGS_DEPTH (args) >= TMPL_ARGS_DEPTH (extra_args),
+ 0);
+
+ /* If *all* the new arguments will be the EXTRA_ARGS, just return
+ them. */
+ if (TMPL_ARGS_DEPTH (args) == TMPL_ARGS_DEPTH (extra_args))
+ return extra_args;
+
/* For the moment, we make ARGS look like it contains fewer levels. */
TREE_VEC_LENGTH (args) -= TMPL_ARGS_DEPTH (extra_args);
*************** coerce_template_parms (parms, arglist, i
*** 2545,2559 ****
int require_all_arguments;
{
int nparms, nargs, i, lost = 0;
! tree vec = NULL_TREE;
!
! if (arglist == NULL_TREE)
! nargs = 0;
! else if (TREE_CODE (arglist) == TREE_VEC)
! nargs = TREE_VEC_LENGTH (arglist);
! else
! nargs = list_length (arglist);
nparms = TREE_VEC_LENGTH (parms);
if (nargs > nparms
--- 2557,2567 ----
int require_all_arguments;
{
int nparms, nargs, i, lost = 0;
! tree inner_args;
! tree vec;
+ inner_args = innermost_args (arglist);
+ nargs = NUM_TMPL_ARGS (inner_args);
nparms = TREE_VEC_LENGTH (parms);
if (nargs > nparms
*************** coerce_template_parms (parms, arglist, i
*** 2563,2584 ****
{
if (complain)
{
! error ("incorrect number of parameters (%d, should be %d)",
! nargs, nparms);
if (in_decl)
! cp_error_at ("in template expansion for decl `%D'",
! in_decl);
}
return error_mark_node;
}
! if (arglist && TREE_CODE (arglist) == TREE_VEC && nargs == nparms)
! vec = copy_node (arglist);
else
{
vec = make_tree_vec (nparms);
for (i = 0; i < nparms; i++)
{
--- 2571,2612 ----
{
if (complain)
{
! cp_error ("wrong number of template arguments (%d, should be %d)",
! nargs, nparms);
if (in_decl)
! cp_error_at ("provided for `%D'", in_decl);
}
return error_mark_node;
}
! /* Create in VEC the appropriate innermost arguments, and reset
! ARGLIST to contain the complete set of arguments. */
! if (inner_args && TREE_CODE (inner_args) == TREE_VEC && nargs == nparms)
! {
! /* If we already have all the arguments, we can just use them.
! This is an optimization over the code in the `else' branch
! below, and should be functionally identicial. */
! vec = copy_node (inner_args);
! arglist = add_outermost_template_args (arglist, vec);
! }
else
{
+ /* If we don't already have all the arguments we must get what
+ we can from default template arguments. The tricky bit is
+ that previous arguments can influence the default values,
+ e.g.:
+
+ template <class T, class U = T> void foo();
+
+ If we see `foo<int>' we have to come up with an {int, int}
+ vector. */
+
+ tree new_arglist;
+
vec = make_tree_vec (nparms);
+ new_arglist = add_outermost_template_args (arglist, vec);
for (i = 0; i < nparms; i++)
{
*************** coerce_template_parms (parms, arglist, i
*** 2597,2619 ****
}
else if (i < nargs)
{
! arg = TREE_VEC_ELT (arglist, i);
if (arg == error_mark_node)
lost++;
}
else if (TREE_PURPOSE (parm) == NULL_TREE)
{
my_friendly_assert (!require_all_arguments, 0);
break;
}
else if (TREE_CODE (TREE_VALUE (parm)) == TYPE_DECL)
! arg = tsubst (TREE_PURPOSE (parm), vec, in_decl);
else
! arg = tsubst_expr (TREE_PURPOSE (parm), vec, in_decl);
TREE_VEC_ELT (vec, i) = arg;
}
}
for (i = 0; i < nparms; i++)
{
tree arg = TREE_VEC_ELT (vec, i);
--- 2625,2657 ----
}
else if (i < nargs)
{
! arg = TREE_VEC_ELT (inner_args, i);
if (arg == error_mark_node)
lost++;
}
+ /* If no template argument was supplied, look for a default
+ value. */
else if (TREE_PURPOSE (parm) == NULL_TREE)
{
+ /* There was no default value. */
my_friendly_assert (!require_all_arguments, 0);
break;
}
else if (TREE_CODE (TREE_VALUE (parm)) == TYPE_DECL)
! arg = tsubst (TREE_PURPOSE (parm), new_arglist, in_decl);
else
! arg = tsubst_expr (TREE_PURPOSE (parm), new_arglist, in_decl);
TREE_VEC_ELT (vec, i) = arg;
}
+
+ /* We've left ARGLIST intact up to this point, in order to allow
+ iteration through it in the case that it was a TREE_LIST, but
+ from here on it should contain the full set of template
+ arguments. */
+ arglist = new_arglist;
}
+
for (i = 0; i < nparms; i++)
{
tree arg = TREE_VEC_ELT (vec, i);
*************** coerce_template_parms (parms, arglist, i
*** 2772,2778 ****
}
else
{
! tree t = tsubst (TREE_TYPE (parm), vec, in_decl);
if (processing_template_decl)
arg = maybe_fold_nontype_arg (arg);
--- 2810,2816 ----
}
else
{
! tree t = tsubst (TREE_TYPE (parm), arglist, in_decl);
if (processing_template_decl)
arg = maybe_fold_nontype_arg (arg);
*************** lookup_template_class (d1, arglist, in_d
*** 3205,3221 ****
{
/* We have multiple levels of arguments to coerce, at once. */
int i;
tree bound_args = make_tree_vec (parm_depth);
! 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 (bound_args, i) =
! coerce_template_parms (TREE_VALUE (t),
! TREE_VEC_ELT (arglist, i),
! template, 1, 1);
arglist = bound_args;
}
else
--- 3243,3271 ----
{
/* We have multiple levels of arguments to coerce, at once. */
int i;
+ int saved_depth = TMPL_ARGS_DEPTH (arglist);
tree bound_args = make_tree_vec (parm_depth);
! for (i = saved_depth,
t = DECL_TEMPLATE_PARMS (template);
! i > 0 && t != NULL_TREE;
--i, t = TREE_CHAIN (t))
! {
! tree a = coerce_template_parms (TREE_VALUE (t),
! arglist, template, 1, 1);
! SET_TMPL_ARGS_LEVEL (bound_args, i, a);
!
! /* We temporarily reduce the length of the ARGLIST so
! that coerce_template_parms will see only the arguments
! corresponding to the template parameters it is
! examining. */
! TREE_VEC_LENGTH (arglist)--;
! }
!
! /* Restore the ARGLIST to its full size. */
! TREE_VEC_LENGTH (arglist) = saved_depth;
!
arglist = bound_args;
}
else
*************** tsubst (t, args, in_decl)
*** 4647,4655 ****
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 if (TREE_CODE (t) == TEMPLATE_TEMPLATE_PARM)
{
if (CLASSTYPE_TEMPLATE_INFO (t))
--- 4697,4709 ----
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))
*************** do_type_instantiation (t, storage)
*** 7392,7399 ****
instantiate_decl (tmp);
}
for (tmp = CLASSTYPE_TAGS (t); tmp; tmp = TREE_CHAIN (tmp))
! if (IS_AGGR_TYPE (TREE_VALUE (tmp)))
do_type_instantiation (TYPE_MAIN_DECL (TREE_VALUE (tmp)), storage);
}
}
--- 7446,7467 ----
instantiate_decl (tmp);
}
+ /* In contrast to implicit instantiation, where only the
+ declarations, and not the definitions, of members are
+ instantiated, we have here:
+
+ [temp.explicit]
+
+ The explicit instantiation of a class template specialization
+ implies the instantiation of all of its members not
+ previously explicitly specialized in the translation unit
+ containing the explicit instantiation.
+
+ Of course, we can't instantiate member template classes, since
+ we don't have any arguments for them. */
for (tmp = CLASSTYPE_TAGS (t); tmp; tmp = TREE_CHAIN (tmp))
! if (IS_AGGR_TYPE (TREE_VALUE (tmp))
! && !uses_template_parms (CLASSTYPE_TI_ARGS (TREE_VALUE (tmp))))
do_type_instantiation (TYPE_MAIN_DECL (TREE_VALUE (tmp)), storage);
}
}