decl.c (duplicate_decls): Always merge the old and new patterns for templates...
authorMark Mitchell <mark@markmitchell.com>
Thu, 20 Aug 1998 13:46:53 +0000 (13:46 +0000)
committerMark Mitchell <mmitchel@gcc.gnu.org>
Thu, 20 Aug 1998 13:46:53 +0000 (13:46 +0000)
* 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

gcc/cp/ChangeLog
gcc/cp/decl.c
gcc/cp/pt.c
gcc/testsuite/g++.old-deja/g++.pt/friend30.C [new file with mode: 0644]

index fb09d6510dac0388bb7423b0b58c610d40818d30..942db4bef26715c0bf63b699d41670159960a464 100644 (file)
@@ -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
index 5e6efa4997824d13a05c1063eaff96811be82391..ad3585b20ab1f708f5d84ee4e974395d3bf00786 100644 (file)
@@ -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.
index 7bdd03c9d8754046a8c376978b645a69f5f19641..a04921cfb81799174a66aa92d02e8e69420b0dbd 100644 (file)
@@ -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 (file)
index 0000000..61dd8fc
--- /dev/null
@@ -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*);