From: lerdsuwa Date: Sat, 22 Nov 2003 06:49:21 +0000 (+0000) Subject: PR c++/5369 X-Git-Tag: upstream/4.9.2~75175 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=7bdfc61c6c541a1106590fad3bd377ae7dd7cfb3;p=platform%2Fupstream%2Flinaro-gcc.git 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 (is_specialization_of_friend): New function. (uses_template_parms_level): 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. (is_specialization_of_friend): Likewise. * 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@73833 138bc75d-0d04-0410-961f-82ee72b054a4 --- diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index a27679f..d047b0a 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,20 @@ +2003-11-22 Kriang Lerdsuwanakij + + 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 (is_specialization_of_friend): New function. + (uses_template_parms_level): 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. + (is_specialization_of_friend): Likewise. + 2003-11-21 Mark Mitchell PR c++/12515 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 75245ab..80414db 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -3718,7 +3718,7 @@ extern void maybe_make_one_only (tree); 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 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); @@ -3877,6 +3877,7 @@ extern void redeclare_class_template (tree, tree); 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 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); @@ -3894,6 +3895,7 @@ extern int is_member_template (tree); extern int comp_template_parms (tree, tree); extern int template_class_depth (tree); extern int is_specialization_of (tree, tree); +extern bool is_specialization_of_friend (tree, tree); extern int comp_template_args (tree, tree); extern void maybe_process_partial_specialization (tree); extern void maybe_check_template_type (tree); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index b247274..a1b320f 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -3756,7 +3756,9 @@ start_decl (tree declarator, } else { - tree field = check_classfn (context, decl); + tree field = check_classfn (context, decl, + processing_template_decl + > template_class_depth (context)); if (field && duplicate_decls (decl, field)) decl = field; } @@ -5661,7 +5663,9 @@ grokfndecl (tree ctype, { tree old_decl; - old_decl = check_classfn (ctype, 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 --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index 5f1076a..b7774c4 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -643,10 +643,12 @@ check_java_method (tree method) /* 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. */ + 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) +check_classfn (tree ctype, tree function, bool template_header_p) { int ix; int is_template; @@ -669,7 +671,7 @@ check_classfn (tree ctype, tree function) /* OK, is this a definition of a member template? */ is_template = (TREE_CODE (function) == TEMPLATE_DECL - || (processing_template_decl - template_class_depth (ctype))); + || template_header_p); ix = lookup_fnfields_1 (complete_type (ctype), DECL_CONSTRUCTOR_P (function) ? ctor_identifier : diff --git a/gcc/cp/friend.c b/gcc/cp/friend.c index e954700..8605321 100644 --- a/gcc/cp/friend.c +++ b/gcc/cp/friend.c @@ -60,25 +60,15 @@ is_friend (tree type, tree supplicant) tree friends = FRIEND_DECLS (list); for (; friends ; friends = TREE_CHAIN (friends)) { - if (TREE_VALUE (friends) == NULL_TREE) - continue; + tree friend = TREE_VALUE (friends); - if (supplicant == TREE_VALUE (friends)) - return 1; + if (friend == NULL_TREE) + continue; - /* 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)))) + if (supplicant == friend) return 1; - if (TREE_CODE (TREE_VALUE (friends)) == TEMPLATE_DECL - && is_specialization_of (supplicant, - TREE_VALUE (friends))) + if (is_specialization_of_friend (supplicant, friend)) return 1; } break; @@ -338,8 +328,6 @@ do_friend (tree ctype, tree declarator, tree decl, tree parmdecls, 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; @@ -353,39 +341,70 @@ do_friend (tree ctype, tree declarator, tree decl, tree parmdecls, if (TREE_CODE (decl) != FUNCTION_DECL) abort (); - is_friend_template = PROCESSING_REAL_TEMPLATE_DECL_P (); - if (ctype) { + /* CLASS_TEMPLATE_DEPTH counts the number of template headers for + the enclosing class. FRIEND_DEPTH counts the number of template + headers used for this friend declaration. TEMPLATE_MEMBER_P is + true if a template header in FRIEND_DEPTH is intended for + DECLARATOR. For example, the code + + template struct A { + template struct B { + template template + friend void C::f(W); + }; + }; + + will eventually give the following results + + 1. CLASS_TEMPLATE_DEPTH equals 2 (for `T' and `U'). + 2. FRIEND_DEPTH equals 2 (for `V' and `W'). + 3. TEMPLATE_MEMBER_P is true (for `W'). */ + + int class_template_depth = template_class_depth (current_class_type); + int friend_depth = processing_template_decl - class_template_depth; + /* We will figure this out later. */ + bool template_member_p = false; + 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) + if (flags == NO_SPECIAL && 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, /*complain=*/true); + if (friend_depth) + { + if (!uses_template_parms_level (ctype, class_template_depth + + friend_depth)) + template_member_p = true; + } + /* 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)) + if (class_template_depth + || COMPLETE_TYPE_P (ctype) + || TYPE_BEING_DEFINED (ctype)) { - decl = check_classfn (ctype, decl); + if (DECL_TEMPLATE_INFO (decl)) + /* DECL is a template specialization. No need to + build a new TEMPLATE_DECL. */ + ; + else if (class_template_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, /*complain=*/true); @@ -398,6 +417,8 @@ do_friend (tree ctype, tree declarator, tree decl, tree parmdecls, @@ 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 --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 5b96938..9f73174 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -876,6 +876,140 @@ is_specialization_of (tree decl, tree tmpl) return 0; } +/* Returns nonzero iff DECL is a specialization of friend declaration + FRIEND according to [temp.friend]. */ + +bool +is_specialization_of_friend (tree decl, tree friend) +{ + bool need_template = true; + int template_depth; + + my_friendly_assert (TREE_CODE (decl) == FUNCTION_DECL, 0); + + /* For [temp.friend/6] when FRIEND is an ordinary member function + of a template class, we want to check if DECL is a specialization + if this. */ + if (TREE_CODE (friend) == FUNCTION_DECL + && DECL_TEMPLATE_INFO (friend) + && !DECL_USE_TEMPLATE (friend)) + { + friend = DECL_TI_TEMPLATE (friend); + need_template = false; + } + + /* There is nothing to do if this is not a template friend. */ + if (TREE_CODE (friend) != TEMPLATE_DECL) + return 0; + + if (is_specialization_of (decl, friend)) + return 1; + + /* [temp.friend/6] + A member of a class template may be declared to be a friend of a + non-template class. In this case, the corresponding member of + every specialization of the class template is a friend of the + class granting friendship. + + For example, given a template friend declaration + + template friend void A::f(); + + the member function below is considered a friend + + template <> struct A { + void f(); + }; + + For this type of template friend, TEMPLATE_DEPTH below will be + non-zero. To determine if DECL is a friend of FRIEND, we first + check if the enclosing class is a specialization of another. */ + + template_depth = template_class_depth (DECL_CONTEXT (friend)); + if (template_depth + && DECL_CLASS_SCOPE_P (decl) + && is_specialization_of (TYPE_NAME (DECL_CONTEXT (decl)), + CLASSTYPE_TI_TEMPLATE (DECL_CONTEXT (friend)))) + { + /* Next, we check the members themselves. In order to handle + a few tricky cases like + + template friend void A::g(T t); + template template friend void A::h(); + + we need to figure out what ARGS is (corresponding to `T' in above + examples) from DECL for later processing. */ + + tree context = DECL_CONTEXT (decl); + tree args = NULL_TREE; + int current_depth = 0; + while (current_depth < template_depth) + { + if (CLASSTYPE_TEMPLATE_INFO (context)) + { + if (current_depth == 0) + args = TYPE_TI_ARGS (context); + else + args = add_to_template_args (TYPE_TI_ARGS (context), args); + current_depth++; + } + context = TYPE_CONTEXT (context); + } + + if (TREE_CODE (decl) == FUNCTION_DECL) + { + bool is_template; + tree friend_type; + tree decl_type; + tree friend_args_type; + tree decl_args_type; + + /* Make sure that both DECL and FRIEND are templates or + non-templates. */ + is_template = DECL_TEMPLATE_INFO (decl) + && PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (decl)); + if (need_template ^ is_template) + return 0; + else if (is_template) + { + /* If both are templates, check template paramter list. */ + tree friend_parms + = tsubst_template_parms (DECL_TEMPLATE_PARMS (friend), + args, tf_none); + if (!comp_template_parms + (DECL_TEMPLATE_PARMS (DECL_TI_TEMPLATE (decl)), + friend_parms)) + return 0; + + decl_type = TREE_TYPE (DECL_TI_TEMPLATE (decl)); + } + else + decl_type = TREE_TYPE (decl); + + friend_type = tsubst_function_type (TREE_TYPE (friend), args, + tf_none, NULL_TREE); + if (friend_type == error_mark_node) + return 0; + + /* Check if return types match. */ + if (!same_type_p (TREE_TYPE (decl_type), TREE_TYPE (friend_type))) + return 0; + + /* Check if function parameter types match, ignoring the + `this' parameter. */ + friend_args_type = TYPE_ARG_TYPES (friend_type); + decl_args_type = TYPE_ARG_TYPES (decl_type); + if (DECL_NONSTATIC_MEMBER_FUNCTION_P (friend)) + friend_args_type = TREE_CHAIN (friend_args_type); + if (DECL_NONSTATIC_MEMBER_FUNCTION_P (decl)) + decl_args_type = TREE_CHAIN (decl_args_type); + if (compparms (decl_args_type, friend_args_type)) + return 1; + } + } + return 0; +} + /* Register the specialization SPEC as a specialization of TMPL with the indicated ARGS. Returns SPEC, or an equivalent prior declaration, if available. */ @@ -2861,10 +2995,8 @@ push_template_decl_real (tree decl, int is_friend) /* 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)) + if (uses_template_parms_level (TREE_TYPE (TREE_TYPE (tmpl)), + depth)) DECL_TEMPLATE_CONV_FN_P (tmpl) = 1; } } @@ -4602,12 +4734,22 @@ for_each_template_parm (tree t, tree_fn_t fn, void* data, htab_t visited) 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); +} + static int tinst_depth; extern int max_tinst_depth; #ifdef GATHER_STATISTICS @@ -4917,7 +5059,7 @@ tsubst_friend_function (tree decl, tree args) /* 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); + new_friend, false); if (fn) new_friend = fn; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 73ffd70..c339a0d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,16 @@ +2003-11-22 Kriang Lerdsuwanakij + + 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. + 2003-11-21 Mark Mitchell PR c++/12515 diff --git a/gcc/testsuite/g++.dg/template/memfriend1.C b/gcc/testsuite/g++.dg/template/memfriend1.C new file mode 100644 index 0000000..f454127 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/memfriend1.C @@ -0,0 +1,54 @@ +// { dg-do compile } + +// Copyright (C) 2003 Free Software Foundation +// Contributed by Kriang Lerdsuwanakij + +// Member function of class template as friend + +template struct A +{ + void f(); +}; + +class C { + int i; + template friend void A::f(); +}; + +template struct A +{ + void f(); +}; + +template<> struct A +{ + void f(); +}; + +template void A::f() +{ + C c; + c.i = 0; +} + +template void A::f() +{ + C c; + c.i = 0; +} + +void A::f() +{ + C c; + c.i = 0; +} + +int main() +{ + A a1; + a1.f(); + A a2; + a2.f(); + A a3; + a3.f(); +} diff --git a/gcc/testsuite/g++.dg/template/memfriend2.C b/gcc/testsuite/g++.dg/template/memfriend2.C new file mode 100644 index 0000000..364ad7d --- /dev/null +++ b/gcc/testsuite/g++.dg/template/memfriend2.C @@ -0,0 +1,61 @@ +// { dg-do compile } + +// Copyright (C) 2003 Free Software Foundation +// Contributed by Kriang Lerdsuwanakij + +// Member function template of class template as friend + +template struct A +{ + template void f(); +}; + +class C { + int i; + template template friend void A::f(); +}; + +template struct A +{ + template void f(); +}; + +template <> struct A +{ + template void f(); +}; + +template template void A::f() +{ + C c; + c.i = 0; +} + +template template void A::f() +{ + C c; + c.i = 0; +} + +template void A::f() +{ + C c; + c.i = 0; +} + +template <> void A::f() +{ + C c; + c.i = 0; +} + +int main() +{ + A a1; + a1.f(); + A a2; + a2.f(); + A a3; + a3.f(); + a3.f(); +} diff --git a/gcc/testsuite/g++.dg/template/memfriend3.C b/gcc/testsuite/g++.dg/template/memfriend3.C new file mode 100644 index 0000000..3ea8c84 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/memfriend3.C @@ -0,0 +1,55 @@ +// { dg-do compile } + +// Copyright (C) 2003 Free Software Foundation +// Contributed by Kriang Lerdsuwanakij + +// Member function of class template as friend + +template struct A +{ + void f(T); +}; + +class C { + int i; + template friend void A::f(T); +}; + +template struct A +{ + void f(T*); +}; + +template<> struct A +{ + void f(char); +}; + +template void A::f(T) +{ + C c; + c.i = 0; +} + +template void A::f(T*) +{ + C c; + c.i = 0; +} + +void A::f(char) +{ + C c; + c.i = 0; +} + +int main() +{ + A a1; + a1.f(0); + A a2; + int *p = 0; + a2.f(p); + A a3; + a3.f('a'); +} diff --git a/gcc/testsuite/g++.dg/template/memfriend4.C b/gcc/testsuite/g++.dg/template/memfriend4.C new file mode 100644 index 0000000..5c006fe --- /dev/null +++ b/gcc/testsuite/g++.dg/template/memfriend4.C @@ -0,0 +1,63 @@ +// { dg-do compile } + +// Copyright (C) 2003 Free Software Foundation +// Contributed by Kriang Lerdsuwanakij + +// Member function of class template as friend + +template struct A +{ + template void f(); +}; + +class C { + int i; + template template friend void A::f(); +}; + +template struct A +{ + template void f(); +}; + +template<> struct A +{ + template void f(); +}; + +template template void A::f() +{ + C c; + c.i = 0; +} + +template template void A::f() +{ + C c; + c.i = 0; +} + +template void A::f() +{ + C c; + c.i = 0; +} + +template <> void A::f<'b'>() +{ + C c; + c.i = 0; +} + +int d2 = 0; + +int main() +{ + A a1; + a1.f<0>(); + A a2; + a2.f<&d2>(); + A a3; + a3.f<'a'>(); + a3.f<'b'>(); +} diff --git a/gcc/testsuite/g++.dg/template/memfriend5.C b/gcc/testsuite/g++.dg/template/memfriend5.C new file mode 100644 index 0000000..38c2fb9 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/memfriend5.C @@ -0,0 +1,31 @@ +// { dg-do compile } + +// Copyright (C) 2003 Free Software Foundation +// Contributed by Kriang Lerdsuwanakij + +// Member template function of member class template as friend + +template struct A { + template struct B { + template void f(V); + }; +}; + +class X { + int i; + template template template + friend void A::B::f(V); +}; + +template template template + void A::B::f(V) +{ + X x; + x.i = 0; +} + +int main() +{ + A::B a1; + a1.f(0); +} diff --git a/gcc/testsuite/g++.dg/template/memfriend6.C b/gcc/testsuite/g++.dg/template/memfriend6.C new file mode 100644 index 0000000..21d7996 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/memfriend6.C @@ -0,0 +1,23 @@ +// { dg-do compile } + +// Copyright (C) 2003 Free Software Foundation +// Contributed by Kriang Lerdsuwanakij + +// Member function of class template as friend +// Erroneous case: mismatch during declaration + +template struct A { + template void f(U); // { dg-error "candidate" } + void g(); // { dg-error "candidate" } + void h(); // { dg-error "candidate" } + void i(int); // { dg-error "candidate" } +}; + +class C { + int ii; + template friend void A::f(U); // { dg-error "not match" } + template template + friend void A::g(); // { dg-error "not match" } + template friend int A::h(); // { dg-error "not match" } + template friend void A::i(char); // { dg-error "not match" } +}; diff --git a/gcc/testsuite/g++.dg/template/memfriend7.C b/gcc/testsuite/g++.dg/template/memfriend7.C new file mode 100644 index 0000000..aed0295 --- /dev/null +++ b/gcc/testsuite/g++.dg/template/memfriend7.C @@ -0,0 +1,133 @@ +// { dg-do compile } + +// Copyright (C) 2003 Free Software Foundation +// Contributed by Kriang Lerdsuwanakij + +// Member function of class template as friend +// Erroneous case: mismatch during specialization + +template struct A { + template void f(U); + void g(); + void h(); + void i(int); + template void j(); +}; + +class C { + int ii; // { dg-error "private" } + template template + friend void A::f(V); + template friend void A::g(); + template friend void A::h(); + template friend void A::i(int); + template template + friend void A::j(); +}; + +template struct A { + void f(int); + template void g(); + int h(); + void i(char); + template void j(); +}; + +template void A::f(int) +{ + C c; + c.ii = 0; // { dg-error "context" } +} + +template template void A::g() +{ + C c; + c.ii = 0; // { dg-error "context" } +} + +template int A::h() +{ + C c; + c.ii = 0; // { dg-error "context" } +} + +template void A::i(char) +{ + C c; + c.ii = 0; // { dg-error "context" } +} + +template template void A::j() +{ + C c; + c.ii = 0; // { dg-error "context" } +} + +template <> struct A { + void f(int); + template void g(); + int h(); + void i(char); + template void j(); +}; + +void A::f(int) +{ + C c; + c.ii = 0; // { dg-error "context" } +} + +template void A::g() +{ + C c; + c.ii = 0; // { dg-error "context" } +} + +template <> void A::g() +{ + C c; + c.ii = 0; // { dg-error "context" } +} + +int A::h() +{ + C c; + c.ii = 0; // { dg-error "context" } +} + +void A::i(char) +{ + C c; + c.ii = 0; // { dg-error "context" } +} + +template void A::j() +{ + C c; + c.ii = 0; // { dg-error "context" } +} + +template <> void A::j<0>() +{ + C c; + c.ii = 0; // { dg-error "context" } +} + +int main() +{ + A a1; + a1.f(0); // { dg-error "instantiated" } + a1.g(); // { dg-error "instantiated" } + a1.g(); // { dg-error "instantiated" } + a1.h(); // { dg-error "instantiated" } + a1.i('a'); // { dg-error "instantiated" } + a1.j<1>(); // { dg-error "instantiated" } + A a2; + a2.f(0); + a2.g(); // { dg-error "instantiated" } + a2.g(); + a2.h(); + a2.i('a'); + a2.j<1>(); // { dg-error "instantiated" } + a2.j<0>(); +} diff --git a/gcc/testsuite/g++.dg/template/memfriend8.C b/gcc/testsuite/g++.dg/template/memfriend8.C new file mode 100644 index 0000000..886096b --- /dev/null +++ b/gcc/testsuite/g++.dg/template/memfriend8.C @@ -0,0 +1,25 @@ +// { dg-do compile } + +// Origin: Martin Sebor + +// PR c++/5369: Member function of class template as friend + +template +struct S +{ + int foo () { + return S::bar (); + } + +private: + + template + friend int S::foo (); + + static int bar () { return 0; } +}; + +int main () +{ + S().foo (); +} diff --git a/gcc/testsuite/g++.old-deja/g++.pt/friend44.C b/gcc/testsuite/g++.old-deja/g++.pt/friend44.C index c82c7e7..1f79172 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/friend44.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/friend44.C @@ -23,7 +23,7 @@ public: template int A::f (T) { B b; - return b.a; // { dg-bogus "" "" { xfail *-*-* } } + return b.a; } template int A::AI::f (T)