This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
PATCH for friend/template ICE
- To: egcs-patches at cygnus dot com
- Subject: PATCH for friend/template ICE
- From: Mark Mitchell <mark at markmitchell dot com>
- Date: Thu, 20 Aug 1998 13:59:17 -0700
- Cc: Jason Merrill <jason at cygnus dot com>, Brendan Kehoe <brendan at cygnus dot com>
- Reply-to: mark at markmitchell dot com
Here's a patch that fixes the bug you (Brendan) reported earlier
involving getline. (The semantics of global friend templates is one of
the hardest parts of template instantiation to get right, IMHO.)
--
Mark Mitchell mark@markmitchell.com
Mark Mitchell Consulting http://www.markmitchell.com
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.
Index: testsuite/g++.old-deja/g++.pt/friend30.C
===================================================================
RCS file: friend30.C
diff -N friend30.C
*** /dev/null Mon Dec 31 20:00:00 1979
--- friend30.C Thu Aug 20 13:27:48 1998
***************
*** 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*);
cvs server: Diffing cp
Index: cp/decl.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/decl.c,v
retrieving revision 1.182
diff -c -p -r1.182 decl.c
*** decl.c 1998/08/19 15:14:55 1.182
--- decl.c 1998/08/20 20:28:55
*************** duplicate_decls (newdecl, olddecl)
*** 2982,2998 ****
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);
return 1;
}
--- 2982,2996 ----
if (TREE_CODE (newdecl) == TEMPLATE_DECL)
{
! 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;
}
*************** duplicate_decls (newdecl, olddecl)
*** 3067,3072 ****
--- 3065,3073 ----
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: cp/pt.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/pt.c,v
retrieving revision 1.178
diff -c -p -r1.178 pt.c
*** pt.c 1998/08/13 17:01:58 1.178
--- pt.c 1998/08/20 20:38:17
*************** tsubst_decl (t, args, type, in_decl)
*** 4847,4853 ****
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);
/* Check to see if we already have this specialization. */
spec = retrieve_specialization (gen_tmpl, argvec);
--- 4847,4854 ----
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 (DECL_TEMPLATE_RESULT (gen_tmpl)),
! args, in_decl);
/* Check to see if we already have this specialization. */
spec = retrieve_specialization (gen_tmpl, argvec);
*************** do_decl_instantiation (declspecs, declar
*** 7460,7466 ****
else if (DECL_TEMPLATE_SPECIALIZATION (decl))
/* [temp.spec]
! No program shall both explicit instantiation and explicit
specialize a template. */
{
cp_error ("explicit instantiation of `%#D' after", decl);
--- 7461,7467 ----
else if (DECL_TEMPLATE_SPECIALIZATION (decl))
/* [temp.spec]
! No program shall both explicitly instantiate and explicitly
specialize a template. */
{
cp_error ("explicit instantiation of `%#D' after", decl);
*************** regenerate_decl_from_template (decl, tmp
*** 7649,7654 ****
--- 7650,7658 ----
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);
*************** regenerate_decl_from_template (decl, tmp
*** 7667,7681 ****
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);
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,
DECL_TI_TEMPLATE (decl));
popclass (1);
}
--- 7671,7721 ----
register_specialization for it. */
my_friendly_assert (unregistered, 0);
! /* 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), subst_args,
DECL_TI_TEMPLATE (decl));
popclass (1);
}
*************** instantiate_decl (d)
*** 7747,7762 ****
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));
)
! td = DECL_TI_TEMPLATE (td);
code_pattern = DECL_TEMPLATE_RESULT (td);
--- 7787,7846 ----
if (! push_tinst_level (d))
return d;
! /* 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)));
)
! {
! /* 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);