summaryrefslogtreecommitdiff
path: root/gcc/cp/friend.c
diff options
context:
space:
mode:
authorKriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>2004-10-20 16:20:50 +0000
committerKriang Lerdsuwanakij <lerdsuwa@gcc.gnu.org>2004-10-20 16:20:50 +0000
commitb939a02360cf41893436921e319c4283f2d6edb5 (patch)
tree36d5919ab016d6c55b8dee09fb15a76c348df75e /gcc/cp/friend.c
parent23517e6b4ea01d0af35984f8473a235a29ff93c7 (diff)
downloadgcc-b939a02360cf41893436921e319c4283f2d6edb5.tar.gz
re PR c++/13495 (Friendship to class nested within a template is broken)
PR c++/13495 * decl.c (make_unbound_class_template): Add PARM_LIST parameter. * cp-tree.h (make_unbound_class_template): Adjust prototype. * parser.c (cp_parser_lookup_name): Adjust call to make_unbound_class_template. (cp_parser_single_declaration): Handle member class of class template as template friend parsing correctly. * friend.c (is_friend): Call is_specialization_of_friend for template friend class. (make_friend_class): Handle member class of class template as template friend. * pt.c (is_specialization_of_friend): Likewise. (instantiate_class_template): Likewise. (tsubst): Adjust call to make_unbound_class_template. * g++.dg/template/memfriend9.C: New test. * g++.dg/template/memfriend10.C: Likewise. * g++.dg/template/memfriend11.C: Likewise. * g++.dg/template/memfriend12.C: Likewise. * g++.dg/template/memfriend13.C: Likewise. * g++.dg/template/memfriend14.C: Likewise. * g++.dg/template/memfriend15.C: Likewise. * g++.dg/template/memfriend16.C: Likewise. * g++.dg/template/memfriend17.C: Likewise. * g++.old-deja/g++.pt/friend44.C: Remove bogus error. From-SVN: r89335
Diffstat (limited to 'gcc/cp/friend.c')
-rw-r--r--gcc/cp/friend.c113
1 files changed, 99 insertions, 14 deletions
diff --git a/gcc/cp/friend.c b/gcc/cp/friend.c
index 6ab9d731ca5..2d177a084f3 100644
--- a/gcc/cp/friend.c
+++ b/gcc/cp/friend.c
@@ -92,7 +92,7 @@ is_friend (tree type, tree supplicant)
tree t = TREE_VALUE (list);
if (TREE_CODE (t) == TEMPLATE_DECL ?
- is_specialization_of (TYPE_MAIN_DECL (supplicant), t) :
+ is_specialization_of_friend (TYPE_MAIN_DECL (supplicant), t) :
same_type_p (supplicant, t))
return 1;
}
@@ -197,7 +197,31 @@ void
make_friend_class (tree type, tree friend_type, bool complain)
{
tree classes;
- int is_template_friend;
+
+ /* 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,
+ defined inside the `if' block for TYPENAME_TYPE case, 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 class C<V>::D;
+ };
+ };
+
+ 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').
+
+ The friend is a template friend iff FRIEND_DEPTH is nonzero. */
+
+ int class_template_depth = template_class_depth (type);
+ int friend_depth = processing_template_decl - class_template_depth;
if (! IS_AGGR_TYPE (friend_type))
{
@@ -205,7 +229,7 @@ make_friend_class (tree type, tree friend_type, bool complain)
return;
}
- if (processing_template_decl > template_class_depth (type))
+ if (friend_depth)
/* If the TYPE is a template then it makes sense for it to be
friends with itself; this means that each instantiation is
friends with all other instantiations. */
@@ -221,8 +245,6 @@ make_friend_class (tree type, tree friend_type, bool complain)
friend_type);
return;
}
-
- is_template_friend = 1;
}
else if (same_type_p (type, friend_type))
{
@@ -231,8 +253,6 @@ make_friend_class (tree type, tree friend_type, bool complain)
type);
return;
}
- else
- is_template_friend = 0;
/* [temp.friend]
@@ -240,13 +260,75 @@ make_friend_class (tree type, tree friend_type, bool complain)
class template, a specialization of a function template or
class template, or an ordinary (nontemplate) function or
class. */
- if (!is_template_friend)
+ if (!friend_depth)
;/* ok */
else if (TREE_CODE (friend_type) == TYPENAME_TYPE)
{
- /* template <class T> friend typename S<T>::X; */
- error ("typename type %q#T declared %<friend%>", friend_type);
- return;
+ if (TREE_CODE (TYPENAME_TYPE_FULLNAME (friend_type))
+ == TEMPLATE_ID_EXPR)
+ {
+ /* template <class U> friend class T::X<U>; */
+ /* [temp.friend]
+ Friend declarations shall not declare partial
+ specializations. */
+ error ("partial specialization %qT declared %<friend%>",
+ friend_type);
+ return;
+ }
+ else
+ {
+ /* We will figure this out later. */
+ bool template_member_p = false;
+
+ tree ctype = TYPE_CONTEXT (friend_type);
+ tree name = TYPE_IDENTIFIER (friend_type);
+ tree decl;
+
+ if (!uses_template_parms_level (ctype, class_template_depth
+ + friend_depth))
+ template_member_p = true;
+
+ if (class_template_depth)
+ {
+ /* We rely on tsubst_friend_class to check the
+ validity of the declaration later. */
+ if (template_member_p)
+ friend_type
+ = make_unbound_class_template (ctype,
+ name,
+ current_template_parms,
+ tf_error);
+ else
+ friend_type
+ = make_typename_type (ctype, name, tf_error);
+ }
+ else
+ {
+ decl = lookup_member (ctype, name, 0, true);
+ if (!decl)
+ {
+ error ("%qT is not a member of %qT", name, ctype);
+ return;
+ }
+ if (template_member_p && !DECL_CLASS_TEMPLATE_P (decl))
+ {
+ error ("%qT is not a member class template of %qT",
+ name, ctype);
+ cp_error_at ("%qD declared here", decl);
+ return;
+ }
+ if (!template_member_p && (TREE_CODE (decl) != TYPE_DECL
+ || !CLASS_TYPE_P (TREE_TYPE (decl))))
+ {
+ error ("%qT is not a nested class of %qT",
+ name, ctype);
+ cp_error_at ("%qD declared here", decl);
+ return;
+ }
+
+ friend_type = CLASSTYPE_TI_TEMPLATE (TREE_TYPE (decl));
+ }
+ }
}
else if (TREE_CODE (friend_type) == TEMPLATE_TYPE_PARM)
{
@@ -260,10 +342,13 @@ make_friend_class (tree type, tree friend_type, bool complain)
error ("%q#T is not a template", friend_type);
return;
}
-
- if (is_template_friend)
+ else
+ /* template <class T> friend class A; where A is a template */
friend_type = CLASSTYPE_TI_TEMPLATE (friend_type);
+ if (friend_type == error_mark_node)
+ return;
+
/* See if it is already a friend. */
for (classes = CLASSTYPE_FRIEND_CLASSES (type);
classes;
@@ -297,7 +382,7 @@ make_friend_class (tree type, tree friend_type, bool complain)
CLASSTYPE_FRIEND_CLASSES (type)
= tree_cons (NULL_TREE, friend_type, CLASSTYPE_FRIEND_CLASSES (type));
- if (is_template_friend)
+ if (TREE_CODE (friend_type) == TEMPLATE_DECL)
friend_type = TREE_TYPE (friend_type);
if (!uses_template_parms (type))
CLASSTYPE_BEFRIENDING_CLASSES (friend_type)