summaryrefslogtreecommitdiffstats
path: root/gcc/cp/friend.c
diff options
context:
space:
mode:
authorlerdsuwa <lerdsuwa@138bc75d-0d04-0410-961f-82ee72b054a4>2003-11-22 06:49:21 +0000
committerlerdsuwa <lerdsuwa@138bc75d-0d04-0410-961f-82ee72b054a4>2003-11-22 06:49:21 +0000
commit7bdfc61c6c541a1106590fad3bd377ae7dd7cfb3 (patch)
tree235f9fa2a81fd346b1ecc91dda40c6d2e542d41d /gcc/cp/friend.c
parent76ef802b587509cd345aafa926b65ce7d5c0c899 (diff)
downloadppe42-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.c89
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.
OpenPOWER on IntegriCloud