diff options
author | Mark Mitchell <mark@markmitchell.com> | 1998-08-20 13:46:53 +0000 |
---|---|---|
committer | Mark Mitchell <mmitchel@gcc.gnu.org> | 1998-08-20 13:46:53 +0000 |
commit | 4d85e00e38bd7c6775904c004499d808aa7a3ee1 (patch) | |
tree | 0e96b25738fc8d44f5034c0ec7390633c1d566da | |
parent | 293bcdc970c9509e8079c4ee96efc1c693be2d9d (diff) | |
download | gcc-4d85e00e38bd7c6775904c004499d808aa7a3ee1.zip gcc-4d85e00e38bd7c6775904c004499d808aa7a3ee1.tar.gz gcc-4d85e00e38bd7c6775904c004499d808aa7a3ee1.tar.bz2 |
decl.c (duplicate_decls): Always merge the old and new patterns for templates...
* decl.c (duplicate_decls): Always merge the old and new patterns
for templates, regardless of whether or not the new one has
DECL_INITIAL. Don't throw away specializations. Merge
DECL_SAVED_TREE.
* pt.c (tsubst_decl): Use the right pattern when calculating the
complete args for a new template instance.
(do_decl_instantiation): Fix typo in comment.
(regenerate_decl_from_template): Deal with tricky friend template
case.
(instantiate_decl): Likewise.
From-SVN: r21876
-rw-r--r-- | gcc/cp/ChangeLog | 13 | ||||
-rw-r--r-- | gcc/cp/decl.c | 23 | ||||
-rw-r--r-- | gcc/cp/pt.c | 112 | ||||
-rw-r--r-- | gcc/testsuite/g++.old-deja/g++.pt/friend30.C | 18 |
4 files changed, 141 insertions, 25 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index fb09d65..942db4b 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,16 @@ +1998-08-20 Mark Mitchell <mark@markmitchell.com> + + * decl.c (duplicate_decls): Always merge the old and new patterns + for templates, regardless of whether or not the new one has + DECL_INITIAL. Don't throw away specializations. Merge + DECL_SAVED_TREE. + * pt.c (tsubst_decl): Use the right pattern when calculating the + complete args for a new template instance. + (do_decl_instantiation): Fix typo in comment. + (regenerate_decl_from_template): Deal with tricky friend template + case. + (instantiate_decl): Likewise. + Thu Aug 20 09:09:45 1998 Jeffrey A Law (law@cygnus.com) * init.c (build_builtin_delete_call): Add missing assemble_external diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 5e6efa4..ad3585b 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -2982,17 +2982,15 @@ duplicate_decls (newdecl, olddecl) if (TREE_CODE (newdecl) == TEMPLATE_DECL) { - if (DECL_INITIAL (DECL_TEMPLATE_RESULT (olddecl)) == NULL_TREE) - { - if (! duplicate_decls (DECL_TEMPLATE_RESULT (newdecl), - DECL_TEMPLATE_RESULT (olddecl))) - cp_error ("invalid redeclaration of %D", newdecl); - TREE_TYPE (olddecl) = TREE_TYPE (DECL_TEMPLATE_RESULT (olddecl)); - DECL_TEMPLATE_PARMS (olddecl) = DECL_TEMPLATE_PARMS (newdecl); - DECL_TEMPLATE_INFO (olddecl) = DECL_TEMPLATE_INFO (newdecl); - } - DECL_TEMPLATE_SPECIALIZATIONS (newdecl) - = DECL_TEMPLATE_SPECIALIZATIONS (olddecl); + if (! duplicate_decls (DECL_TEMPLATE_RESULT (newdecl), + DECL_TEMPLATE_RESULT (olddecl))) + cp_error ("invalid redeclaration of %D", newdecl); + TREE_TYPE (olddecl) = TREE_TYPE (DECL_TEMPLATE_RESULT (olddecl)); + DECL_TEMPLATE_PARMS (olddecl) = DECL_TEMPLATE_PARMS (newdecl); + DECL_TEMPLATE_INFO (olddecl) = DECL_TEMPLATE_INFO (newdecl); + DECL_TEMPLATE_SPECIALIZATIONS (olddecl) + = chainon (DECL_TEMPLATE_SPECIALIZATIONS (olddecl), + DECL_TEMPLATE_SPECIALIZATIONS (newdecl)); return 1; } @@ -3067,6 +3065,9 @@ duplicate_decls (newdecl, olddecl) DECL_INITIAL (newdecl) = DECL_INITIAL (olddecl); DECL_SOURCE_FILE (newdecl) = DECL_SOURCE_FILE (olddecl); DECL_SOURCE_LINE (newdecl) = DECL_SOURCE_LINE (olddecl); + if (DECL_LANG_SPECIFIC (newdecl) + && DECL_LANG_SPECIFIC (olddecl)) + DECL_SAVED_TREE (newdecl) = DECL_SAVED_TREE (olddecl); } /* Merge the section attribute. diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 7bdd03c..a04921c 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -4847,7 +4847,8 @@ tsubst_decl (t, args, type, in_decl) specialization, and the complete set of arguments used to specialize R. */ gen_tmpl = most_general_template (DECL_TI_TEMPLATE (t)); - argvec = tsubst (DECL_TI_ARGS (t), args, in_decl); + argvec = tsubst (DECL_TI_ARGS (DECL_TEMPLATE_RESULT (gen_tmpl)), + args, in_decl); /* Check to see if we already have this specialization. */ spec = retrieve_specialization (gen_tmpl, argvec); @@ -7460,7 +7461,7 @@ do_decl_instantiation (declspecs, declarator, storage) else if (DECL_TEMPLATE_SPECIALIZATION (decl)) /* [temp.spec] - No program shall both explicit instantiation and explicit + No program shall both explicitly instantiate and explicitly specialize a template. */ { cp_error ("explicit instantiation of `%#D' after", decl); @@ -7649,6 +7650,9 @@ regenerate_decl_from_template (decl, tmpl) tree code_pattern; tree new_decl; tree gen_tmpl; + tree subst_args; + int args_depth; + int parms_depth; int unregistered; args = DECL_TI_ARGS (decl); @@ -7667,15 +7671,51 @@ regenerate_decl_from_template (decl, tmpl) register_specialization for it. */ my_friendly_assert (unregistered, 0); - /* Do the substitution to get the new declaration. */ - new_decl = tsubst (code_pattern, args, NULL_TREE); + /* Do the substitution to get the new declaration. Normally, of + course, we want the full set of ARGS. However, one peculiar case + is code like this: + + template <class T> struct S { + template <class U> friend void f(); + }; + template <class U> friend void f() {} + template S<int>; + template void f<double>(); + + Here, the ARGS for the instantiation of will be {int, double}. + But, we only need as many ARGS as there are levels of template + parameters in CODE_PATTERN. We are careful not to get fooled + into reducing the ARGS in situations like: + + template <class T> struct S { template <class U> void f(U); } + template <class T> template <> void S<T>::f(int) {} + + which we can spot because the innermost template args for the + CODE_PATTERN don't use any template parameters. */ + args_depth = TMPL_ARGS_DEPTH (args); + parms_depth = + TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (DECL_TI_TEMPLATE (code_pattern))); + if (args_depth > parms_depth + && !DECL_TEMPLATE_SPECIALIZATION (code_pattern)) + { + int i; + + subst_args = make_temp_vec (parms_depth); + for (i = 0; i < parms_depth; ++i) + TREE_VEC_ELT (subst_args, i) = + TREE_VEC_ELT (args, i + (args_depth - parms_depth)); + } + else + subst_args = args; + + new_decl = tsubst (code_pattern, subst_args, NULL_TREE); 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, + tsubst_expr (DECL_INITIAL (code_pattern), subst_args, DECL_TI_TEMPLATE (decl)); popclass (1); } @@ -7747,16 +7787,60 @@ instantiate_decl (d) if (! push_tinst_level (d)) return d; - for (td = tmpl; - DECL_TEMPLATE_INSTANTIATION (td) - /* This next clause handles friend templates defined inside - class templates. The friend templates are not really - instantiations from the point of view of the language, but - they are instantiations from the point of view of the - compiler. */ - || (DECL_TEMPLATE_INFO (td) && !DECL_TEMPLATE_SPECIALIZATION (td)); + /* Set TD to the template whose DECL_TEMPLATE_RESULT is the pattern + for the instantiation. This is not always the most general + template. Consider, for example: + + template <class T> + struct S { template <class U> void f(); + template <> void f<int>(); }; + + and an instantiation of S<double>::f<int>. We want TD to be the + specialization S<T>::f<int>, not the more general S<T>::f<U>. */ + td = tmpl; + for (td = tmpl; + /* An instantiation cannot have a definition, so we need a + more general template. */ + DECL_TEMPLATE_INSTANTIATION (td) + /* We must also deal with friend templates. Given: + + template <class T> struct S { + template <class U> friend void f() {}; + }; + + S<int>::f<U> say, is not an instantiation of S<T>::f<U>, + so far as the language is concerned, but that's still + where we get the pattern for the instantiation from. On + ther hand, if the definition comes outside the class, say: + + template <class T> struct S { + template <class U> friend void f(); + }; + template <class U> friend void f() {} + + we don't need to look any further. That's what the check for + DECL_INITIAL is for. */ + || (TREE_CODE (d) == FUNCTION_DECL + && DECL_TEMPLATE_INFO (td) + && !DECL_TEMPLATE_SPECIALIZATION (td) + && !DECL_INITIAL (DECL_TEMPLATE_RESULT (td))); ) - td = DECL_TI_TEMPLATE (td); + { + /* The present template, TD, should not be a definition. If it + were a definition, we should be using it! Note that we + cannot restructure the loop to just keep going until we find + a template with a definition, since that might go too far if + a specialization was declared, but not defined. */ + my_friendly_assert (!(TREE_CODE (d) == FUNCTION_DECL + && DECL_INITIAL (DECL_TEMPLATE_RESULT (td))), + 0); + my_friendly_assert (!(TREE_CODE (d) == VAR_DECL + && !DECL_IN_AGGR_P (DECL_TEMPLATE_RESULT (td))), + 0); + + /* Fetch the more general template. */ + td = DECL_TI_TEMPLATE (td); + } code_pattern = DECL_TEMPLATE_RESULT (td); diff --git a/gcc/testsuite/g++.old-deja/g++.pt/friend30.C b/gcc/testsuite/g++.old-deja/g++.pt/friend30.C new file mode 100644 index 0000000..61dd8fc --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.pt/friend30.C @@ -0,0 +1,18 @@ +// Build don't link: + +template <class T, class U> +struct S { + template <class X, class Y, class Z> + friend X f(X, Y, Z); +}; + +template <class X, class Y, class Z> +X f(X x, Y, Z) { + return x; +} + +template char f(char, long, short); +template char* f(char*, long*, short*); +template class S<int, double>; +template class S<void*, double>; +template double* f(double*, long*, short*); |