This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[C++ PATCH] Fix PR5369 (Member function of class template as friend)
- From: Kriang Lerdsuwanakij <lerdsuwa at users dot sourceforge dot net>
- To: <gcc-patches at gcc dot gnu dot org>
- Date: Mon, 11 Aug 2003 21:51:45 +0700 (ICT)
- Subject: [C++ PATCH] Fix PR5369 (Member function of class template as friend)
- Reply-to: <lerdsuwa at users dot sourceforge dot net>
Hi
Currently GCC cannot handle template friend declarations described
in 14.5.3/6. This patch add a support for the case when a member
function is declared as template friend, i.e.
template <class T> struct A {
void f();
};
class C {
template <class T> friend void A<T>::f();
};
The main parts of the changes are in do_friend and is_friend.
In do_friend, I add several checks to determine the exact type of
template friend, whether the template header is for the scope like:
template <class T> friend void A<T>::f();
or for the member like:
template <class T> friend void A::f(T);
and act accordingly. I add a function parameter to check_classfn
reflect the necessity to distinguish between two cases of template
header above.
Other changes, uses_template_parms_* are simply helper functions
for diagnostics.
Patch tested on i686-pc-linux-gnu with no regressions. OK to
commit to mainline?
--Kriang
2003-08-10 Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
PR c++/5369
* friend.c (is_friend): Handle member function of a class
template as template friend.
(do_friend): Likewise.
* decl2.c (check_classfn): Add template_header_p parameter.
* decl.c (start_decl): Adjust check_classfn call.
(grokfndecl): Likewise.
* pt.c (template_parm_index_range): New struct.
(tsubst_function_type): Remove static.
(template_parm_index_range_p): New function.
(uses_template_parms_level): Likewise.
(uses_template_parms_range): Likewise.
(push_template_decl_real): Use uses_template_parms_level.
(tsubst_friend_function): Adjust check_classfn call.
* cp-tree.h (check_classfn): Adjust declaration.
(uses_template_parms_level): Add declaration.
(uses_template_parms_range): Likewise.
(tsubst_function_type): Likewise.
2003-08-10 Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
PR c++/5369
* g++.dg/template/memfriend1.C: New test.
* g++.dg/template/memfriend2.C: Likewise.
* g++.dg/template/memfriend3.C: Likewise.
* g++.dg/template/memfriend4.C: Likewise.
* g++.dg/template/memfriend5.C: Likewise.
* g++.dg/template/memfriend6.C: Likewise.
* g++.dg/template/memfriend7.C: Likewise.
* g++.dg/template/memfriend8.C: Likewise.
* g++.old-deja/g++.pt/friend44.C: Remove a bogus error.
diff -cprN gcc-main-save/gcc/cp/cp-tree.h gcc-main-new/gcc/cp/cp-tree.h
*** gcc-main-save/gcc/cp/cp-tree.h Wed Aug 6 21:39:56 2003
--- gcc-main-new/gcc/cp/cp-tree.h Sun Aug 10 22:12:41 2003
*************** extern void maybe_make_one_only (tree);
*** 3780,3786 ****
extern void grokclassfn (tree, tree, enum overload_flags, tree);
extern tree grok_array_decl (tree, tree);
extern tree delete_sanity (tree, tree, int, int);
! extern tree check_classfn (tree, tree);
extern void check_member_template (tree);
extern tree grokfield (tree, tree, tree, tree, tree);
extern tree grokbitfield (tree, tree, tree);
--- 3780,3786 ----
extern void grokclassfn (tree, tree, enum overload_flags, tree);
extern tree grok_array_decl (tree, tree);
extern tree delete_sanity (tree, tree, int, int);
! extern tree check_classfn (tree, tree, bool);
extern void check_member_template (tree);
extern tree grokfield (tree, tree, tree, tree, tree);
extern tree grokbitfield (tree, tree, tree);
*************** extern void redeclare_class_template
*** 3956,3961 ****
--- 3956,3963 ----
extern tree lookup_template_class (tree, tree, tree, tree, int, tsubst_flags_t);
extern tree lookup_template_function (tree, tree);
extern int uses_template_parms (tree);
+ extern int uses_template_parms_level (tree, int);
+ extern int uses_template_parms_range (tree, int, int);
extern tree instantiate_class_template (tree);
extern tree instantiate_template (tree, tree, tsubst_flags_t);
extern int fn_type_unification (tree, tree, tree, tree, tree, unification_kind_t, int);
*************** extern void maybe_check_template_type
*** 3979,3984 ****
--- 3981,3987 ----
extern tree most_specialized_instantiation (tree);
extern void print_candidates (tree);
extern int instantiate_pending_templates (void);
+ extern tree tsubst_function_type (tree, tree, tsubst_flags_t, tree);
extern tree tsubst_default_argument (tree, tree, tree);
extern tree tsubst_copy_and_build (tree, tree, tsubst_flags_t, tree, bool);
extern tree most_general_template (tree);
diff -cprN gcc-main-save/gcc/cp/decl.c gcc-main-new/gcc/cp/decl.c
*** gcc-main-save/gcc/cp/decl.c Thu Aug 7 21:33:46 2003
--- gcc-main-new/gcc/cp/decl.c Sun Aug 10 19:19:47 2003
*************** start_decl (tree declarator,
*** 7048,7054 ****
}
else
{
! tree field = check_classfn (context, decl);
if (field && duplicate_decls (decl, field))
decl = field;
}
--- 7048,7056 ----
}
else
{
! tree field = check_classfn (context, decl,
! processing_template_decl
! > template_class_depth (context));
if (field && duplicate_decls (decl, field))
decl = field;
}
*************** grokfndecl (tree ctype,
*** 9006,9012 ****
{
tree old_decl;
! old_decl = check_classfn (ctype, decl);
if (old_decl && TREE_CODE (old_decl) == TEMPLATE_DECL)
/* Because grokfndecl is always supposed to return a
--- 9008,9016 ----
{
tree old_decl;
! old_decl = check_classfn (ctype, decl,
! processing_template_decl
! > template_class_depth (ctype));
if (old_decl && TREE_CODE (old_decl) == TEMPLATE_DECL)
/* Because grokfndecl is always supposed to return a
diff -cprN gcc-main-save/gcc/cp/decl2.c gcc-main-new/gcc/cp/decl2.c
*** gcc-main-save/gcc/cp/decl2.c Wed Aug 6 21:39:56 2003
--- gcc-main-new/gcc/cp/decl2.c Sun Aug 10 18:24:16 2003
*************** check_java_method (tree method)
*** 655,664 ****
/* Sanity check: report error if this function FUNCTION is not
really a member of the class (CTYPE) it is supposed to belong to.
! CNAME is the same here as it is for grokclassfn above. */
tree
! check_classfn (tree ctype, tree function)
{
int ix;
int is_template;
--- 655,666 ----
/* Sanity check: report error if this function FUNCTION is not
really a member of the class (CTYPE) it is supposed to belong to.
! CNAME is the same here as it is for grokclassfn above.
! TEMPLATE_HEADER_P is true when this declaration comes with a
! template header. */
tree
! check_classfn (tree ctype, tree function, bool template_header_p)
{
int ix;
int is_template;
*************** check_classfn (tree ctype, tree function
*** 681,687 ****
/* OK, is this a definition of a member template? */
is_template = (TREE_CODE (function) == TEMPLATE_DECL
! || (processing_template_decl - template_class_depth (ctype)));
ix = lookup_fnfields_1 (complete_type (ctype),
DECL_CONSTRUCTOR_P (function) ? ctor_identifier :
--- 683,689 ----
/* OK, is this a definition of a member template? */
is_template = (TREE_CODE (function) == TEMPLATE_DECL
! || template_header_p);
ix = lookup_fnfields_1 (complete_type (ctype),
DECL_CONSTRUCTOR_P (function) ? ctor_identifier :
diff -cprN gcc-main-save/gcc/cp/friend.c gcc-main-new/gcc/cp/friend.c
*** gcc-main-save/gcc/cp/friend.c Thu Jul 17 22:46:21 2003
--- gcc-main-new/gcc/cp/friend.c Mon Aug 11 19:10:54 2003
*************** is_friend (tree type, tree supplicant)
*** 60,85 ****
tree friends = FRIEND_DECLS (list);
for (; friends ; friends = TREE_CHAIN (friends))
{
! if (TREE_VALUE (friends) == NULL_TREE)
! continue;
! if (supplicant == TREE_VALUE (friends))
! return 1;
! /* Temporarily, we are more lenient to deal with
! nested friend functions, for which there can be
! more than one FUNCTION_DECL, despite being the
! same function. When that's fixed, this bit can
! go. */
! if (DECL_FUNCTION_MEMBER_P (supplicant)
! && same_type_p (TREE_TYPE (supplicant),
! TREE_TYPE (TREE_VALUE (friends))))
return 1;
! if (TREE_CODE (TREE_VALUE (friends)) == TEMPLATE_DECL
! && is_specialization_of (supplicant,
! TREE_VALUE (friends)))
! return 1;
}
break;
}
--- 60,112 ----
tree friends = FRIEND_DECLS (list);
for (; friends ; friends = TREE_CHAIN (friends))
{
! tree friend = TREE_VALUE (friends);
! if (friend == NULL_TREE)
! continue;
! if (supplicant == friend)
return 1;
! /* For [temp.friend/6] when FRIEND is an ordinary member
! function of a template class, we want to check if
! SUPPLICANT is a specialization if this. */
! if (TREE_CODE (friend) == FUNCTION_DECL
! && DECL_TEMPLATE_INFO (friend)
! && !DECL_USE_TEMPLATE (friend))
! friend = DECL_TI_TEMPLATE (friend);
!
! if (TREE_CODE (friend) == TEMPLATE_DECL)
! {
! if (is_specialization_of (supplicant, friend))
! return 1;
!
! /* For [temp.friend/6] when FRIEND is a member
! function template. First, we check if the
! class is a specialization of another. */
! if (DECL_CLASS_SCOPE_P (friend)
! && DECL_CLASS_SCOPE_P (supplicant)
! && is_specialization_of
! (TYPE_NAME (DECL_CONTEXT (supplicant)),
! TYPE_NAME (DECL_CONTEXT (friend))))
! {
! /* Next, we check the members themselves.
! Although we can decide if a class is a
! specialization of another easily, their
! members can be totally different. We need
! to compare function parameters and return
! types to get correct result. */
! tree args = TYPE_TI_ARGS
! (DECL_CONTEXT (supplicant));
! tree fn_type = tsubst_function_type
! (TREE_TYPE (friend), args,
! tf_none, NULL_TREE);
!
! if (same_type_p (TREE_TYPE (supplicant),
! fn_type))
! return 1;
! }
! }
}
break;
}
*************** do_friend (tree ctype, tree declarator,
*** 328,335 ****
tree attrlist, enum overload_flags flags, tree quals,
int funcdef_flag)
{
- int is_friend_template = 0;
-
/* Every decl that gets here is a friend of something. */
DECL_FRIEND_P (decl) = 1;
--- 355,360 ----
*************** do_friend (tree ctype, tree declarator,
*** 343,381 ****
if (TREE_CODE (decl) != FUNCTION_DECL)
abort ();
- is_friend_template = PROCESSING_REAL_TEMPLATE_DECL_P ();
-
if (ctype)
{
tree cname = TYPE_NAME (ctype);
if (TREE_CODE (cname) == TYPE_DECL)
cname = DECL_NAME (cname);
/* A method friend. */
! if (flags == NO_SPECIAL && ctype && declarator == cname)
DECL_CONSTRUCTOR_P (decl) = 1;
/* This will set up DECL_ARGUMENTS for us. */
grokclassfn (ctype, decl, flags, quals);
! if (is_friend_template)
! decl = DECL_TI_TEMPLATE (push_template_decl (decl));
! else if (DECL_TEMPLATE_INFO (decl))
! ;
! else if (template_class_depth (current_class_type))
! decl = push_template_decl_real (decl, /*is_friend=*/1);
!
! /* We can't do lookup in a type that involves template
! parameters. Instead, we rely on tsubst_friend_function
! to check the validity of the declaration later. */
! if (processing_template_decl)
! add_friend (current_class_type, decl);
/* A nested class may declare a member of an enclosing class
to be a friend, so we do lookup here even if CTYPE is in
the process of being defined. */
! else if (COMPLETE_TYPE_P (ctype) || TYPE_BEING_DEFINED (ctype))
{
! decl = check_classfn (ctype, decl);
if (decl)
add_friend (current_class_type, decl);
--- 368,472 ----
if (TREE_CODE (decl) != FUNCTION_DECL)
abort ();
if (ctype)
{
+ /* CLASS_DEPTH counts the number of template headers for the
+ enclosing class. FRIEND_DEPTH counts the number of template
+ headers used for this friend declaration. */
+ int class_depth = template_class_depth (current_class_type);
+ int friend_depth = processing_template_decl - class_depth;
+
+ /* TEMPLATE_SCOPE_P is true if a template header in FRIEND_DEPTH
+ is for CTYPE. TEMPLATE_MEMBER_P is true if a template header
+ ind FRIEND_DEPTH is for DECLARATOR. */
+ bool template_scope_p;
+ bool template_member_p;
+
tree cname = TYPE_NAME (ctype);
if (TREE_CODE (cname) == TYPE_DECL)
cname = DECL_NAME (cname);
/* A method friend. */
! if (flags == NO_SPECIAL && declarator == cname)
DECL_CONSTRUCTOR_P (decl) = 1;
/* This will set up DECL_ARGUMENTS for us. */
grokclassfn (ctype, decl, flags, quals);
! /* We need to sort out what the template header is for,
! the type or the member function. Assume the declaration
! is valid for now. We will deal with erroneous cases later. */
! if (friend_depth == 2)
! {
! /* template <class T> template <class U>
! friend void A<T>::f(U); */
! template_scope_p = true;
! template_member_p = true;
! }
! else if (friend_depth == 1)
! {
! if (!uses_template_parms_level (ctype, class_depth + 1))
! {
! /* template <class T> friend void A::f(T); */
! template_scope_p = false;
! template_member_p = true;
! }
! else
! {
! /* template <class T> friend void A<T>::f();
!
! Note that we also cover the case like
! template <class T> friend void A<T>::f(T);
! here because we can declare `f' as
! template <class T> class A { void f(T); }; */
! template_scope_p = true;
! template_member_p = false;
! }
! }
! else if (friend_depth == 0)
! {
! template_scope_p = false;
! template_member_p = false;
! }
! else
! {
! /* When FRIEND_DEPTH > 2. */
! error ("too many template headers for a template friend");
! return decl;
! }
!
! if (template_scope_p
! && uses_template_parms_range (TYPE_CONTEXT (ctype),
! class_depth + 1,
! class_depth + friend_depth))
! {
! /* Handle invalid cases like
! template <class T> template <class U>
! friend A<T>::B<U>::f(); */
! error ("scope must not be template parameter dependent");
! return decl;
! }
!
/* A nested class may declare a member of an enclosing class
to be a friend, so we do lookup here even if CTYPE is in
the process of being defined. */
! if (class_depth
! || COMPLETE_TYPE_P (ctype)
! || TYPE_BEING_DEFINED (ctype))
{
! if (DECL_TEMPLATE_INFO (decl))
! /* DECL is a template specialization. No need to
! build a new TEMPLATE_DECL. */
! ;
! else if (class_depth)
! /* We rely on tsubst_friend_function to check the
! validity of the declaration later. */
! decl = push_template_decl_real (decl, /*is_friend=*/1);
! else
! decl = check_classfn (ctype, decl, template_member_p);
!
! if (template_member_p && decl && TREE_CODE (decl) == FUNCTION_DECL)
! decl = DECL_TI_TEMPLATE (decl);
if (decl)
add_friend (current_class_type, decl);
*************** do_friend (tree ctype, tree declarator,
*** 388,393 ****
--- 479,486 ----
@@ or possibly a friend from a base class ?!? */
else if (TREE_CODE (decl) == FUNCTION_DECL)
{
+ int is_friend_template = PROCESSING_REAL_TEMPLATE_DECL_P ();
+
/* Friends must all go through the overload machinery,
even though they may not technically be overloaded.
diff -cprN gcc-main-save/gcc/cp/pt.c gcc-main-new/gcc/cp/pt.c
*** gcc-main-save/gcc/cp/pt.c Wed Aug 6 21:39:56 2003
--- gcc-main-new/gcc/cp/pt.c Mon Aug 11 19:06:57 2003
*************** Boston, MA 02111-1307, USA. */
*** 47,52 ****
--- 47,58 ----
returning an int. */
typedef int (*tree_fn_t) (tree, void*);
+ typedef struct template_parm_index_range_s
+ {
+ HOST_WIDE_INT lower;
+ HOST_WIDE_INT upper;
+ } template_parm_index_range;
+
/* The PENDING_TEMPLATES is a TREE_LIST of templates whose
instantiations have been deferred, either because their definitions
were not yet available, or because we were putting off doing the work.
*************** static int template_class_depth_real (tr
*** 144,150 ****
static tree tsubst_aggr_type (tree, tree, tsubst_flags_t, tree, int);
static tree tsubst_decl (tree, tree, tree, tsubst_flags_t);
static tree tsubst_arg_types (tree, tree, tsubst_flags_t, tree);
- static tree tsubst_function_type (tree, tree, tsubst_flags_t, tree);
static void check_specialization_scope (void);
static tree process_partial_specialization (tree);
static void set_current_access_from_decl (tree);
--- 150,155 ----
*************** template_parm_this_level_p (tree t, void
*** 2620,2625 ****
--- 2628,2652 ----
return level == this_level;
}
+ /* Worker for , called via
+ for_each_template_parm.
+ DATA is really an int, indicating the
+ level of the parameters we are interested in. If T is a template
+ parameter of that level, return nonzero. */
+
+ static int
+ template_parm_index_range_p (tree t, void* data)
+ {
+ template_parm_index_range *p = (template_parm_index_range *)data;
+ int level;
+
+ if (TREE_CODE (t) == TEMPLATE_PARM_INDEX)
+ level = TEMPLATE_PARM_LEVEL (t);
+ else
+ level = TEMPLATE_TYPE_LEVEL (t);
+ return level >= p->lower && level <= p->upper;
+ }
+
/* Creates a TEMPLATE_DECL for the indicated DECL using the template
parameters given by current_template_args, or reuses a
previously existing one, if appropriate. Returns the DECL, or an
*************** push_template_decl_real (tree decl, int
*** 2847,2856 ****
/* It is a conversion operator. See if the type converted to
depends on innermost template operands. */
! if (for_each_template_parm (TREE_TYPE (TREE_TYPE (tmpl)),
! template_parm_this_level_p,
! &depth,
! NULL))
DECL_TEMPLATE_CONV_FN_P (tmpl) = 1;
}
}
--- 2874,2881 ----
/* It is a conversion operator. See if the type converted to
depends on innermost template operands. */
! if (uses_template_parms_level (TREE_TYPE (TREE_TYPE (tmpl)),
! depth))
DECL_TEMPLATE_CONV_FN_P (tmpl) = 1;
}
}
*************** for_each_template_parm (tree t, tree_fn_
*** 4604,4615 ****
--- 4629,4662 ----
return result;
}
+ /* Returns true if T depends on any template parameter. */
+
int
uses_template_parms (tree t)
{
return for_each_template_parm (t, 0, 0, NULL);
}
+ /* Returns true if T depends on any template parameter with level LEVEL. */
+
+ int
+ uses_template_parms_level (tree t, int level)
+ {
+ return for_each_template_parm (t, template_parm_this_level_p, &level, NULL);
+ }
+
+ /* Returns true if T depends on any template parameter with level between
+ LOWER and UPPER, inclusive. */
+
+ int
+ uses_template_parms_range (tree t, int lower, int upper)
+ {
+ template_parm_index_range r;
+ r.lower = lower;
+ r.upper = upper;
+ return for_each_template_parm (t, template_parm_index_range_p, &r, NULL);
+ }
+
static int tinst_depth;
extern int max_tinst_depth;
#ifdef GATHER_STATISTICS
*************** tsubst_friend_function (tree decl, tree
*** 4919,4925 ****
/* Check to see that the declaration is really present, and,
possibly obtain an improved declaration. */
tree fn = check_classfn (DECL_CONTEXT (new_friend),
! new_friend);
if (fn)
new_friend = fn;
--- 4966,4972 ----
/* Check to see that the declaration is really present, and,
possibly obtain an improved declaration. */
tree fn = check_classfn (DECL_CONTEXT (new_friend),
! new_friend, false);
if (fn)
new_friend = fn;
*************** tsubst_arg_types (tree arg_types,
*** 6282,6288 ****
ated, at which point a program is ill-formed if the substitution
results in an invalid type.] */
! static tree
tsubst_function_type (tree t,
tree args,
tsubst_flags_t complain,
--- 6329,6335 ----
ated, at which point a program is ill-formed if the substitution
results in an invalid type.] */
! tree
tsubst_function_type (tree t,
tree args,
tsubst_flags_t complain,
diff -cprN gcc-main-save/gcc/testsuite/g++.dg/template/memfriend1.C gcc-main-new/gcc/testsuite/g++.dg/template/memfriend1.C
*** gcc-main-save/gcc/testsuite/g++.dg/template/memfriend1.C Thu Jan 1 07:00:00 1970
--- gcc-main-new/gcc/testsuite/g++.dg/template/memfriend1.C Sun Aug 10 17:58:37 2003
***************
*** 0 ****
--- 1,54 ----
+ // { dg-do compile }
+
+ // Copyright (C) 2003 Free Software Foundation
+ // Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
+
+ // Member function of class template as friend
+
+ template<class T> struct A
+ {
+ void f();
+ };
+
+ template<class T> struct A<T*>
+ {
+ void f();
+ };
+
+ template<> struct A<char>
+ {
+ void f();
+ };
+
+ class C {
+ int i;
+ template<class T> friend void A<T>::f();
+ };
+
+ template<class T> void A<T>::f()
+ {
+ C c;
+ c.i = 0;
+ }
+
+ template<class T> void A<T*>::f()
+ {
+ C c;
+ c.i = 0;
+ }
+
+ void A<char>::f()
+ {
+ C c;
+ c.i = 0;
+ }
+
+ int main()
+ {
+ A<int> a1;
+ a1.f();
+ A<int *> a2;
+ a2.f();
+ A<char> a3;
+ a3.f();
+ }
diff -cprN gcc-main-save/gcc/testsuite/g++.dg/template/memfriend2.C gcc-main-new/gcc/testsuite/g++.dg/template/memfriend2.C
*** gcc-main-save/gcc/testsuite/g++.dg/template/memfriend2.C Thu Jan 1 07:00:00 1970
--- gcc-main-new/gcc/testsuite/g++.dg/template/memfriend2.C Sun Aug 10 17:58:37 2003
***************
*** 0 ****
--- 1,61 ----
+ // { dg-do compile }
+
+ // Copyright (C) 2003 Free Software Foundation
+ // Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
+
+ // Member function template of class template as friend
+
+ template <class T> struct A
+ {
+ template <class U> void f();
+ };
+
+ template <class T> struct A<T*>
+ {
+ template <class U> void f();
+ };
+
+ template <> struct A<char>
+ {
+ template <class U> void f();
+ };
+
+ class C {
+ int i;
+ template <class T> template <class U> friend void A<T>::f();
+ };
+
+ template <class T> template <class U> void A<T>::f()
+ {
+ C c;
+ c.i = 0;
+ }
+
+ template <class T> template <class U> void A<T*>::f()
+ {
+ C c;
+ c.i = 0;
+ }
+
+ template <class U> void A<char>::f()
+ {
+ C c;
+ c.i = 0;
+ }
+
+ template <> void A<char>::f<int>()
+ {
+ C c;
+ c.i = 0;
+ }
+
+ int main()
+ {
+ A<int> a1;
+ a1.f<char>();
+ A<int *> a2;
+ a2.f<char>();
+ A<char> a3;
+ a3.f<char>();
+ a3.f<int>();
+ }
diff -cprN gcc-main-save/gcc/testsuite/g++.dg/template/memfriend3.C gcc-main-new/gcc/testsuite/g++.dg/template/memfriend3.C
*** gcc-main-save/gcc/testsuite/g++.dg/template/memfriend3.C Thu Jan 1 07:00:00 1970
--- gcc-main-new/gcc/testsuite/g++.dg/template/memfriend3.C Sun Aug 10 17:58:37 2003
***************
*** 0 ****
--- 1,28 ----
+ // { dg-do compile }
+
+ // Copyright (C) 2003 Free Software Foundation
+ // Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
+
+ // Member function of class template as friend
+
+ template<class T> struct A
+ {
+ void f(T);
+ };
+
+ class C {
+ int i;
+ template<class T> friend void A<T>::f(T);
+ };
+
+ template<class T> void A<T>::f(T)
+ {
+ C c;
+ c.i = 0;
+ }
+
+ int main()
+ {
+ A<int> a;
+ a.f(0);
+ }
diff -cprN gcc-main-save/gcc/testsuite/g++.dg/template/memfriend4.C gcc-main-new/gcc/testsuite/g++.dg/template/memfriend4.C
*** gcc-main-save/gcc/testsuite/g++.dg/template/memfriend4.C Thu Jan 1 07:00:00 1970
--- gcc-main-new/gcc/testsuite/g++.dg/template/memfriend4.C Sun Aug 10 22:10:47 2003
***************
*** 0 ****
--- 1,21 ----
+ // { dg-do compile }
+
+ // Copyright (C) 2003 Free Software Foundation
+ // Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
+
+ // Member function of class template as friend (erroneous case)
+
+ template <class T> struct A {
+ template <class U> void f(U); // { dg-error "candidate" }
+ };
+
+ class D {
+ int i;
+ template <class U> friend void A<U>::f(U); // { dg-error "not match" }
+ };
+
+ template <class T> template <class U> void A<T>::f(U)
+ {
+ D d;
+ d.i = 0;
+ }
diff -cprN gcc-main-save/gcc/testsuite/g++.dg/template/memfriend5.C gcc-main-new/gcc/testsuite/g++.dg/template/memfriend5.C
*** gcc-main-save/gcc/testsuite/g++.dg/template/memfriend5.C Thu Jan 1 07:00:00 1970
--- gcc-main-new/gcc/testsuite/g++.dg/template/memfriend5.C Sun Aug 10 17:58:37 2003
***************
*** 0 ****
--- 1,17 ----
+ // { dg-do compile }
+
+ // Copyright (C) 2003 Free Software Foundation
+ // Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
+
+ // Member function of class template as friend (erroneous case)
+
+ template <class T> class A {
+ template <class U> class B {
+ void f();
+ };
+ };
+
+ class X {
+ template <class T>
+ friend void A<T>::B<T>::f(); // { dg-error "too few" }
+ };
diff -cprN gcc-main-save/gcc/testsuite/g++.dg/template/memfriend6.C gcc-main-new/gcc/testsuite/g++.dg/template/memfriend6.C
*** gcc-main-save/gcc/testsuite/g++.dg/template/memfriend6.C Thu Jan 1 07:00:00 1970
--- gcc-main-new/gcc/testsuite/g++.dg/template/memfriend6.C Sun Aug 10 17:58:37 2003
***************
*** 0 ****
--- 1,17 ----
+ // { dg-do compile }
+
+ // Copyright (C) 2003 Free Software Foundation
+ // Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
+
+ // Member template function of class template as friend (erroneous case)
+
+ template <class T> class A {
+ template <class U> class B {
+ template <class V> void f(V);
+ };
+ };
+
+ class X {
+ template <class T> template <class U> template <class V>
+ friend void A<T>::B<U>::f(V); // { dg-error "too many" }
+ };
diff -cprN gcc-main-save/gcc/testsuite/g++.dg/template/memfriend7.C gcc-main-new/gcc/testsuite/g++.dg/template/memfriend7.C
*** gcc-main-save/gcc/testsuite/g++.dg/template/memfriend7.C Thu Jan 1 07:00:00 1970
--- gcc-main-new/gcc/testsuite/g++.dg/template/memfriend7.C Sun Aug 10 17:58:37 2003
***************
*** 0 ****
--- 1,17 ----
+ // { dg-do compile }
+
+ // Copyright (C) 2003 Free Software Foundation
+ // Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
+
+ // Member function of class template as friend (erroneous case)
+
+ template <class T> class A {
+ template <class U> class B {
+ void f();
+ };
+ };
+
+ class X {
+ template <class T> template <class U>
+ friend void A<T>::B<U>::f(); // { dg-error "scope" }
+ };
diff -cprN gcc-main-save/gcc/testsuite/g++.dg/template/memfriend8.C gcc-main-new/gcc/testsuite/g++.dg/template/memfriend8.C
*** gcc-main-save/gcc/testsuite/g++.dg/template/memfriend8.C Thu Jan 1 07:00:00 1970
--- gcc-main-new/gcc/testsuite/g++.dg/template/memfriend8.C Sun Aug 10 19:53:25 2003
***************
*** 0 ****
--- 1,25 ----
+ // { dg-do compile }
+
+ // Origin: Martin Sebor <sebor@roguewave.com>
+
+ // PR c++/5369: Member function of class template as friend
+
+ template <class T>
+ struct S
+ {
+ int foo () {
+ return S<int>::bar ();
+ }
+
+ private:
+
+ template <class U>
+ friend int S<U>::foo ();
+
+ static int bar () { return 0; }
+ };
+
+ int main ()
+ {
+ S<char>().foo ();
+ }
diff -cprN gcc-main-save/gcc/testsuite/g++.old-deja/g++.pt/friend44.C gcc-main-new/gcc/testsuite/g++.old-deja/g++.pt/friend44.C
*** gcc-main-save/gcc/testsuite/g++.old-deja/g++.pt/friend44.C Thu May 1 18:35:29 2003
--- gcc-main-new/gcc/testsuite/g++.old-deja/g++.pt/friend44.C Sun Aug 10 19:44:12 2003
*************** public:
*** 23,29 ****
template <class T> int A<T>::f (T)
{
B b;
! return b.a; // { dg-bogus "" "" { xfail *-*-* } }
}
template <class T> int A<T>::AI::f (T)
--- 23,29 ----
template <class T> int A<T>::f (T)
{
B b;
! return b.a;
}
template <class T> int A<T>::AI::f (T)