This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++ PATCH for friends/templates
- To: egcs-patches at cygnus dot com
- Subject: C++ PATCH for friends/templates
- From: Mark Mitchell <mark at markmitchell dot com>
- Date: Mon, 16 Nov 1998 08:37:32 -0800
- Cc: Jason Merrill <jason at cygnus dot com>
- Reply-to: mark at markmitchell dot com
This patch fixes ttp53.C, and also catches illegal redefinitions of
templates in instantiated friend declarations.
--
Mark Mitchell mark@markmitchell.com
Mark Mitchell Consulting http://www.markmitchell.com
1998-11-16 Mark Mitchell <mark@markmitchell.com>
* cp-tree.h (DECL_TEMPLATE_INSTANTIATED): New macro.
* decl.c (duplicate_decls): Remove special-case code to deal with
template friends, and just do the obvious thing.
* pt.c (register_specialization): Tweak for clarity, and also to
clear DECL_INITIAL for an instantiation before it is merged with a
specialization.
(check_explicit_specialization): Fix indentation.
(tsubst_friend_function): Handle both definitions in friend
declaration and outside friend declarations.
(tsubst_decl): Don't clear DECL_INITIAL for an instantiation.
(regenerate_decl_from_template): Tweak accordingly.
(instantiate_decl): Likewise.
Index: testsuite/g++.old-deja/g++.pt/friend36.C
===================================================================
RCS file: friend36.C
diff -N friend36.C
*** /dev/null Mon Dec 31 20:00:00 1979
--- friend36.C Sun Nov 15 19:03:26 1998
***************
*** 0 ****
--- 1,12 ----
+ // Build don't link:
+
+ template <class T>
+ void f(T) {} // ERROR - previously defined here
+
+ template <class U>
+ struct S {
+ template <class T>
+ friend void f(T) {} // ERROR - redeclaration
+ };
+
+ S<int> si;
Index: testsuite/g++.old-deja/g++.pt/ttp53.C
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/testsuite/g++.old-deja/g++.pt/ttp53.C,v
retrieving revision 1.1
diff -c -p -r1.1 ttp53.C
*** ttp53.C 1998/10/11 19:59:27 1.1
--- ttp53.C 1998/11/16 03:03:27
*************** class H{
*** 13,19 ****
public:
#endif
template<template<class, class> class Caster, typename Source>
! static H<Type> cast(const H<Source>& s); // gets bogus error - candidate - XFAIL *-*-*
#ifndef OK
template <typename Target, typename Source>
--- 13,19 ----
public:
#endif
template<template<class, class> class Caster, typename Source>
! static H<Type> cast(const H<Source>& s);
#ifndef OK
template <typename Target, typename Source>
*************** template <class, class> class caster;
*** 26,35 ****
template <typename Target, typename Source>
H<Target> foo(const H<Source>& s){
! return H<Target>::template cast<caster, Source>(s); // gets bogus error - no match - XFAIL *-*-*
}
int main(){
H<int> i;
! foo<const int>(i); // gets bogus error - instantiated from here - XFAIL *-*-*
}
--- 26,35 ----
template <typename Target, typename Source>
H<Target> foo(const H<Source>& s){
! return H<Target>::template cast<caster, Source>(s);
}
int main(){
H<int> i;
! foo<const int>(i);
}
Index: cp-tree.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.170
diff -c -p -r1.170 cp-tree.h
*** cp-tree.h 1998/11/07 12:54:32 1.170
--- cp-tree.h 1998/11/16 15:42:47
*************** Boston, MA 02111-1307, USA. */
*** 65,70 ****
--- 65,71 ----
Usage of DECL_LANG_FLAG_?:
0: DECL_ERROR_REPORTED (in VAR_DECL).
1: C_TYPEDEF_EXPLICITLY_SIGNED (in TYPE_DECL).
+ DECL_TEMPLATE_INSTANTIATED (in a VAR_DECL or a FUNCTION_DECL)
2: DECL_THIS_EXTERN (in VAR_DECL or FUNCTION_DECL).
3: DECL_IN_AGGR_P.
4: DECL_MAYBE_TEMPLATE.
*************** extern int flag_new_for_scope;
*** 1812,1817 ****
--- 1813,1824 ----
/* This function may be a guiding decl for a template. */
#define DECL_MAYBE_TEMPLATE(NODE) DECL_LANG_FLAG_4 (NODE)
+
+ /* Nonzero if this VAR_DECL or FUNCTION_DECL has already been
+ instantiated, i.e. its definition has been generated from the
+ pattern given in the the template. */
+ #define DECL_TEMPLATE_INSTANTIATED(NODE) DECL_LANG_FLAG_1(NODE)
+
/* We know what we're doing with this decl now. */
#define DECL_INTERFACE_KNOWN(NODE) DECL_LANG_FLAG_5 (NODE)
Index: decl.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/decl.c,v
retrieving revision 1.258
diff -c -p -r1.258 decl.c
*** decl.c 1998/11/15 19:24:38 1.258
--- decl.c 1998/11/16 15:42:55
*************** duplicate_decls (newdecl, olddecl)
*** 2989,2997 ****
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);
- if (DECL_TEMPLATE_INFO (newdecl))
- DECL_TEMPLATE_INFO (olddecl) = DECL_TEMPLATE_INFO (newdecl);
DECL_TEMPLATE_SPECIALIZATIONS (olddecl)
= chainon (DECL_TEMPLATE_SPECIALIZATIONS (olddecl),
DECL_TEMPLATE_SPECIALIZATIONS (newdecl));
--- 2989,2994 ----
*************** duplicate_decls (newdecl, olddecl)
*** 3123,3133 ****
DECL_IN_AGGR_P (newdecl) = DECL_IN_AGGR_P (olddecl);
DECL_ACCESS (newdecl) = DECL_ACCESS (olddecl);
DECL_NONCONVERTING_P (newdecl) = DECL_NONCONVERTING_P (olddecl);
! if (DECL_TEMPLATE_INFO (newdecl) == NULL_TREE)
! {
! DECL_TEMPLATE_INFO (newdecl) = DECL_TEMPLATE_INFO (olddecl);
! DECL_USE_TEMPLATE (newdecl) = DECL_USE_TEMPLATE (olddecl);
! }
olddecl_friend = DECL_FRIEND_P (olddecl);
}
--- 3120,3126 ----
DECL_IN_AGGR_P (newdecl) = DECL_IN_AGGR_P (olddecl);
DECL_ACCESS (newdecl) = DECL_ACCESS (olddecl);
DECL_NONCONVERTING_P (newdecl) = DECL_NONCONVERTING_P (olddecl);
! DECL_TEMPLATE_INFO (newdecl) = DECL_TEMPLATE_INFO (olddecl);
olddecl_friend = DECL_FRIEND_P (olddecl);
}
Index: pt.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/pt.c,v
retrieving revision 1.234
diff -c -p -r1.234 pt.c
*** pt.c 1998/11/15 19:24:40 1.234
--- pt.c 1998/11/16 15:43:00
*************** register_specialization (spec, tmpl, arg
*** 831,845 ****
We transform the existing DECL in place so that
any pointers to it become pointers to the
! updated declaration. */
! duplicate_decls (spec, TREE_VALUE (s));
! return TREE_VALUE (s);
}
}
else if (DECL_TEMPLATE_SPECIALIZATION (fn))
{
! duplicate_decls (spec, TREE_VALUE (s));
! return TREE_VALUE (s);
}
}
}
--- 831,852 ----
We transform the existing DECL in place so that
any pointers to it become pointers to the
! updated declaration.
!
! If there was a definition for the template, but
! not for the specialization, we want this to
! look as if there is no definition, and vice
! versa. */
! DECL_INITIAL (fn) = NULL_TREE;
! duplicate_decls (spec, fn);
!
! return fn;
}
}
else if (DECL_TEMPLATE_SPECIALIZATION (fn))
{
! duplicate_decls (spec, fn);
! return fn;
}
}
}
*************** check_explicit_specialization (declarato
*** 1369,1375 ****
/* This is not really a declaration of a specialization.
It's just the name of an instantiation. But, it's not
a request for an instantiation, either. */
! SET_DECL_IMPLICIT_INSTANTIATION (decl);
/* Register this specialization so that we can find it
again. */
--- 1376,1382 ----
/* This is not really a declaration of a specialization.
It's just the name of an instantiation. But, it's not
a request for an instantiation, either. */
! SET_DECL_IMPLICIT_INSTANTIATION (decl);
/* Register this specialization so that we can find it
again. */
*************** tsubst_friend_function (decl, args)
*** 4247,4262 ****
if (DECL_NAMESPACE_SCOPE_P (new_friend))
{
tree old_decl;
! tree new_friend_args;
!
if (TREE_CODE (new_friend) == TEMPLATE_DECL)
! /* This declaration is a `primary' template. */
! DECL_PRIMARY_TEMPLATE (new_friend) = new_friend;
- /* We must save the DECL_TI_ARGS for NEW_FRIEND here because
- pushdecl may call duplicate_decls which will free NEW_FRIEND
- if possible. */
- new_friend_args = DECL_TI_ARGS (new_friend);
old_decl = pushdecl_namespace_level (new_friend);
if (old_decl != new_friend)
--- 4254,4283 ----
if (DECL_NAMESPACE_SCOPE_P (new_friend))
{
tree old_decl;
! tree new_friend_template_info;
! tree new_friend_result_template_info;
! int new_friend_is_defn;
!
! /* We must save some information from NEW_FRIEND before calling
! duplicate decls since that function will free NEW_FRIEND if
! possible. */
! new_friend_template_info = DECL_TEMPLATE_INFO (new_friend);
if (TREE_CODE (new_friend) == TEMPLATE_DECL)
! {
! /* This declaration is a `primary' template. */
! DECL_PRIMARY_TEMPLATE (new_friend) = new_friend;
!
! new_friend_is_defn
! = DECL_INITIAL (DECL_RESULT (new_friend)) != NULL_TREE;
! new_friend_result_template_info
! = DECL_TEMPLATE_INFO (DECL_RESULT (new_friend));
! }
! else
! {
! new_friend_is_defn = DECL_INITIAL (new_friend) != NULL_TREE;
! new_friend_result_template_info = NULL_TREE;
! }
old_decl = pushdecl_namespace_level (new_friend);
if (old_decl != new_friend)
*************** tsubst_friend_function (decl, args)
*** 4295,4330 ****
when `C<int>' is instantiated. Now, `f(int)' is defined
in the class. */
! if (TREE_CODE (old_decl) != TEMPLATE_DECL)
! /* duplicate_decls will take care of this case. */
;
! else
{
! tree t;
!
! for (t = DECL_TEMPLATE_SPECIALIZATIONS (old_decl);
! t != NULL_TREE;
! t = TREE_CHAIN (t))
{
! tree spec = TREE_VALUE (t);
!
! DECL_TI_ARGS (spec)
! = add_outermost_template_args (new_friend_args,
! DECL_TI_ARGS (spec));
! DECL_TI_ARGS (spec)
! = copy_to_permanent (DECL_TI_ARGS (spec));
! }
! /* Now, since specializations are always supposed to
! hang off of the most general template, we must move
! them. */
! t = most_general_template (old_decl);
! if (t != old_decl)
! {
! DECL_TEMPLATE_SPECIALIZATIONS (t)
! = chainon (DECL_TEMPLATE_SPECIALIZATIONS (t),
! DECL_TEMPLATE_SPECIALIZATIONS (old_decl));
! DECL_TEMPLATE_SPECIALIZATIONS (old_decl) = NULL_TREE;
}
}
--- 4316,4370 ----
when `C<int>' is instantiated. Now, `f(int)' is defined
in the class. */
! if (!new_friend_is_defn)
! /* On the other hand, if the in-class declaration does
! *not* provide a definition, then we don't want to alter
! existing definitions. We can just leave everything
! alone. */
;
! else
{
! /* Overwrite whatever template info was there before, if
! any, with the new template information pertaining to
! the declaration. */
! DECL_TEMPLATE_INFO (old_decl) = new_friend_template_info;
!
! if (TREE_CODE (old_decl) != TEMPLATE_DECL)
! /* duplicate_decls will take care of this case. */
! ;
! else
{
! tree t;
! tree new_friend_args;
! DECL_TEMPLATE_INFO (DECL_RESULT (old_decl))
! = new_friend_result_template_info;
!
! new_friend_args = TI_ARGS (new_friend_template_info);
! for (t = DECL_TEMPLATE_SPECIALIZATIONS (old_decl);
! t != NULL_TREE;
! t = TREE_CHAIN (t))
! {
! tree spec = TREE_VALUE (t);
!
! DECL_TI_ARGS (spec)
! = add_outermost_template_args (new_friend_args,
! DECL_TI_ARGS (spec));
! DECL_TI_ARGS (spec)
! = copy_to_permanent (DECL_TI_ARGS (spec));
! }
!
! /* Now, since specializations are always supposed to
! hang off of the most general template, we must move
! them. */
! t = most_general_template (old_decl);
! if (t != old_decl)
! {
! DECL_TEMPLATE_SPECIALIZATIONS (t)
! = chainon (DECL_TEMPLATE_SPECIALIZATIONS (t),
! DECL_TEMPLATE_SPECIALIZATIONS (old_decl));
! DECL_TEMPLATE_SPECIALIZATIONS (old_decl) = NULL_TREE;
! }
}
}
*************** tsubst_decl (t, args, type, in_decl)
*** 5312,5318 ****
DECL_ARGUMENTS (r) = tsubst (DECL_ARGUMENTS (t), args, t);
DECL_MAIN_VARIANT (r) = r;
DECL_RESULT (r) = NULL_TREE;
- DECL_INITIAL (r) = NULL_TREE;
TREE_STATIC (r) = 0;
TREE_PUBLIC (r) = TREE_PUBLIC (t);
--- 5352,5357 ----
*************** regenerate_decl_from_template (decl, tmp
*** 8285,8293 ****
}
if (TREE_CODE (decl) == FUNCTION_DECL)
! /* Convince duplicate_decls to use the DECL_ARGUMENTS from the
! new decl. */
! DECL_INITIAL (new_decl) = error_mark_node;
/* The immediate parent of the new template is still whatever it was
before, even though tsubst sets DECL_TI_TEMPLATE up as the most
--- 8324,8336 ----
}
if (TREE_CODE (decl) == FUNCTION_DECL)
! {
! /* Convince duplicate_decls to use the DECL_ARGUMENTS from the
! new decl. */
! DECL_INITIAL (new_decl) = error_mark_node;
! /* And don't complain about a duplicate definition. */
! DECL_INITIAL (decl) = NULL_TREE;
! }
/* The immediate parent of the new template is still whatever it was
before, even though tsubst sets DECL_TI_TEMPLATE up as the most
*************** regenerate_decl_from_template (decl, tmp
*** 8303,8311 ****
/* Call duplicate decls to merge the old and new declarations. */
duplicate_decls (new_decl, decl);
- if (TREE_CODE (decl) == FUNCTION_DECL)
- DECL_INITIAL (new_decl) = NULL_TREE;
-
/* Now, re-register the specialization. */
register_specialization (decl, gen_tmpl, args);
}
--- 8346,8351 ----
*************** instantiate_decl (d)
*** 8332,8339 ****
my_friendly_assert (TREE_CODE (d) == FUNCTION_DECL
|| TREE_CODE (d) == VAR_DECL, 0);
! if ((TREE_CODE (d) == FUNCTION_DECL && DECL_INITIAL (d))
! || (TREE_CODE (d) == VAR_DECL && !DECL_IN_AGGR_P (d)))
/* D has already been instantiated. It might seem reasonable to
check whether or not D is an explict instantiation, and, if so,
stop here. But when an explicit instantiation is deferred
--- 8372,8378 ----
my_friendly_assert (TREE_CODE (d) == FUNCTION_DECL
|| TREE_CODE (d) == VAR_DECL, 0);
! if (DECL_TEMPLATE_INSTANTIATED (d))
/* D has already been instantiated. It might seem reasonable to
check whether or not D is an explict instantiation, and, if so,
stop here. But when an explicit instantiation is deferred
*************** instantiate_decl (d)
*** 8398,8406 ****
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);
--- 8437,8442 ----
*************** instantiate_decl (d)
*** 8483,8488 ****
--- 8519,8525 ----
}
regenerate_decl_from_template (d, td);
+ DECL_TEMPLATE_INSTANTIATED (d) = 1;
/* We already set the file and line above. Reset them now in case
they changed as a result of calling regenerate_decl_from_template. */