diff options
author | lerdsuwa <lerdsuwa@138bc75d-0d04-0410-961f-82ee72b054a4> | 2003-11-22 06:49:21 +0000 |
---|---|---|
committer | lerdsuwa <lerdsuwa@138bc75d-0d04-0410-961f-82ee72b054a4> | 2003-11-22 06:49:21 +0000 |
commit | 7bdfc61c6c541a1106590fad3bd377ae7dd7cfb3 (patch) | |
tree | 235f9fa2a81fd346b1ecc91dda40c6d2e542d41d /gcc/cp/friend.c | |
parent | 76ef802b587509cd345aafa926b65ce7d5c0c899 (diff) | |
download | ppe42-gcc-7bdfc61c6c541a1106590fad3bd377ae7dd7cfb3.tar.gz ppe42-gcc-7bdfc61c6c541a1106590fad3bd377ae7dd7cfb3.zip |
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
Diffstat (limited to 'gcc/cp/friend.c')
-rw-r--r-- | gcc/cp/friend.c | 89 |
1 files changed, 55 insertions, 34 deletions
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 <class T> struct A { + template <class U> struct B { + template <class V> template <class W> + friend void C<V>::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. |