From 7bdfc61c6c541a1106590fad3bd377ae7dd7cfb3 Mon Sep 17 00:00:00 2001 From: lerdsuwa Date: Sat, 22 Nov 2003 06:49:21 +0000 Subject: 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 --- gcc/cp/friend.c | 89 +++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 55 insertions(+), 34 deletions(-) (limited to 'gcc/cp/friend.c') diff --git a/gcc/cp/friend.c b/gcc/cp/friend.c index e9547005bba..8605321012c 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. -- cgit v1.2.1