aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Mitchell <mark@markmitchell.com>1998-08-20 13:46:53 +0000
committerMark Mitchell <mmitchel@gcc.gnu.org>1998-08-20 13:46:53 +0000
commit4d85e00e38bd7c6775904c004499d808aa7a3ee1 (patch)
tree0e96b25738fc8d44f5034c0ec7390633c1d566da
parent293bcdc970c9509e8079c4ee96efc1c693be2d9d (diff)
downloadgcc-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/ChangeLog13
-rw-r--r--gcc/cp/decl.c23
-rw-r--r--gcc/cp/pt.c112
-rw-r--r--gcc/testsuite/g++.old-deja/g++.pt/friend30.C18
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*);