From e4a84209743bde2f3de26ed67193708e98224f7f Mon Sep 17 00:00:00 2001 From: Mark Mitchell Date: Tue, 4 Aug 1998 11:46:41 +0000 Subject: [PATCH] decl.c (pushtag): Don't mangle the name of a TYPE_DECL if it uses template parameters. * decl.c (pushtag): Don't mangle the name of a TYPE_DECL if it uses template parameters. * 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. * init.c (build_offset_ref): Deal with a TEMPLATE_ID_EXPR whose name is a LOOKUP_EXPR, rather than an IDENTIFIER_NODE. From-SVN: r21609 --- gcc/cp/ChangeLog | 26 +++ gcc/cp/decl.c | 5 +- gcc/cp/init.c | 5 + gcc/cp/method.c | 10 +- gcc/cp/pt.c | 150 +++++++++++++----- gcc/testsuite/g++.old-deja/g++.pt/crash18.C | 23 +++ .../g++.old-deja/g++.pt/memclass16.C | 13 ++ 7 files changed, 184 insertions(+), 48 deletions(-) create mode 100644 gcc/testsuite/g++.old-deja/g++.pt/crash18.C create mode 100644 gcc/testsuite/g++.old-deja/g++.pt/memclass16.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 2d2e7dc6be6..12218d8ae80 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,29 @@ +1998-08-04 Mark Mitchell + + * decl.c (pushtag): Don't mangle the name of a TYPE_DECL if it + uses template parameters. + * 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. + + * init.c (build_offset_ref): Deal with a TEMPLATE_ID_EXPR whose + name is a LOOKUP_EXPR, rather than an IDENTIFIER_NODE. + 1998-08-03 Jason Merrill * method.c (set_mangled_name_for_decl): Change return type to void. diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 68419056fb7..699170a0c92 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -2396,8 +2396,9 @@ pushtag (name, type, globalize) 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 (!uses_template_parms (type)) + DECL_ASSEMBLER_NAME (d) + = get_identifier (build_overload_name (type, 1, 1)); } } if (b->parm_flag == 2) diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 5975320d31f..78b6c5d8cba 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -1547,6 +1547,11 @@ build_offset_ref (type, name) part, we treat this just like a.f. We do remember, however, the template-id that was used. */ name = TREE_OPERAND (orig_name, 0); + + if (TREE_CODE (name) == LOOKUP_EXPR) + /* This can happen during tsubst'ing. */ + name = TREE_OPERAND (name, 0); + my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE, 0); } diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 69ba1b02ea9..16ecbf2d7da 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -862,13 +862,14 @@ build_template_parm_names (parmlist, arglist) 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 (arglist, i); + tree arg = TREE_VEC_ELT (inner_args, i); if (TREE_CODE (parm) == TYPE_DECL) { /* This parameter is a type. */ @@ -919,9 +920,8 @@ build_overload_identifier (name) { /* 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); + 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'); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 3906eb38d99..6775575cb59 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -135,19 +135,6 @@ static int template_class_depth_real PROTO((tree, int)); 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) \ @@ -157,6 +144,14 @@ static int template_class_depth_real PROTO((tree, int)); && 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) \ @@ -177,6 +172,13 @@ static int template_class_depth_real PROTO((tree, int)); #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))) @@ -506,6 +508,16 @@ add_outermost_template_args (args, extra_args) { 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); @@ -2545,15 +2557,11 @@ coerce_template_parms (parms, arglist, in_decl, 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); + tree inner_args; + tree vec; + inner_args = innermost_args (arglist); + nargs = NUM_TMPL_ARGS (inner_args); nparms = TREE_VEC_LENGTH (parms); if (nargs > nparms @@ -2563,22 +2571,42 @@ coerce_template_parms (parms, arglist, in_decl, { if (complain) { - error ("incorrect number of parameters (%d, should be %d)", - nargs, nparms); + cp_error ("wrong number of template arguments (%d, should be %d)", + nargs, nparms); if (in_decl) - cp_error_at ("in template expansion for decl `%D'", - in_decl); + cp_error_at ("provided for `%D'", in_decl); } return error_mark_node; } - if (arglist && TREE_CODE (arglist) == TREE_VEC && nargs == nparms) - vec = copy_node (arglist); + /* 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 void foo(); + + If we see `foo' 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++) { @@ -2597,23 +2625,33 @@ coerce_template_parms (parms, arglist, in_decl, } else if (i < nargs) { - arg = TREE_VEC_ELT (arglist, i); + 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), vec, in_decl); + arg = tsubst (TREE_PURPOSE (parm), new_arglist, in_decl); else - arg = tsubst_expr (TREE_PURPOSE (parm), vec, in_decl); + 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); @@ -2772,7 +2810,7 @@ coerce_template_parms (parms, arglist, in_decl, } else { - tree t = tsubst (TREE_TYPE (parm), vec, in_decl); + tree t = tsubst (TREE_TYPE (parm), arglist, in_decl); if (processing_template_decl) arg = maybe_fold_nontype_arg (arg); @@ -3205,17 +3243,29 @@ lookup_template_class (d1, arglist, in_decl, context, entering_scope) { /* 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 = TREE_VEC_LENGTH (arglist) - 1, + for (i = saved_depth, t = DECL_TEMPLATE_PARMS (template); - i >= 0 && t != NULL_TREE; + 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); + { + 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 @@ -4647,9 +4697,13 @@ tsubst (t, args, in_decl) 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)); + { + 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)) @@ -7392,8 +7446,22 @@ do_type_instantiation (t, storage) 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))) + 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); } } diff --git a/gcc/testsuite/g++.old-deja/g++.pt/crash18.C b/gcc/testsuite/g++.old-deja/g++.pt/crash18.C new file mode 100644 index 00000000000..b12c702e856 --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.pt/crash18.C @@ -0,0 +1,23 @@ +// Build don't run: + +template +class foo { + T deft; + + template int priv (U u, T t) { return u - t; } +public: + foo (T t) : deft (t) {} + + template int pub (U u) { + int (foo::*fn) (U, T); + fn = &foo::template priv; + return (this->*fn) (u, deft); + } +}; + +int +main () +{ + foo fff (5); + return fff.pub (3); +} diff --git a/gcc/testsuite/g++.old-deja/g++.pt/memclass16.C b/gcc/testsuite/g++.old-deja/g++.pt/memclass16.C new file mode 100644 index 00000000000..e8e564369e9 --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.pt/memclass16.C @@ -0,0 +1,13 @@ +// Build don't link: + +template +class A { +public: + + typedef enum { X, Y } B; + template class Traits{ }; +}; + + +template class A; +template class A::Traits::X>; -- 2.30.2