/* Help friends in C++.
- Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+ Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
Free Software Foundation, Inc.
This file is part of GCC.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
#include "config.h"
#include "system.h"
context = TYPE_CONTEXT (context))
if (type == context)
return 1;
-
+
list = CLASSTYPE_FRIEND_CLASSES (TREE_TYPE (TYPE_MAIN_DECL (type)));
for (; list ; list = TREE_CHAIN (list))
{
tree t = TREE_VALUE (list);
- if (TREE_CODE (t) == TEMPLATE_DECL ?
- is_specialization_of (TYPE_MAIN_DECL (supplicant), t) :
+ if (TREE_CODE (t) == TEMPLATE_DECL ?
+ is_specialization_of_friend (TYPE_MAIN_DECL (supplicant), t) :
same_type_p (supplicant, t))
return 1;
}
- }
+ }
if (declp && DECL_FUNCTION_MEMBER_P (supplicant))
context = DECL_CONTEXT (supplicant);
tree typedecl;
tree list;
tree name;
+ tree ctx;
if (decl == error_mark_node)
return;
if (decl == TREE_VALUE (friends))
{
if (complain)
- warning ("`%D' is already a friend of class `%T'",
+ warning (0, "%qD is already a friend of class %qT",
decl, type);
return;
}
list = TREE_CHAIN (list);
}
- if (DECL_CLASS_SCOPE_P (decl))
- perform_or_defer_access_check (TYPE_BINFO (DECL_CONTEXT (decl)), decl);
+ ctx = DECL_CONTEXT (decl);
+ if (ctx && CLASS_TYPE_P (ctx) && !uses_template_parms (ctx))
+ perform_or_defer_access_check (TYPE_BINFO (ctx), decl);
maybe_add_class_template_decl_list (type, decl, /*friend_p=*/1);
= tree_cons (DECL_NAME (decl), build_tree_list (NULL_TREE, decl),
DECL_FRIENDLIST (typedecl));
if (!uses_template_parms (type))
- DECL_BEFRIENDING_CLASSES (decl)
+ DECL_BEFRIENDING_CLASSES (decl)
= tree_cons (NULL_TREE, type,
DECL_BEFRIENDING_CLASSES (decl));
}
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))
{
- error ("invalid type `%T' declared `friend'", friend_type);
+ error ("invalid type %qT declared %<friend%>", friend_type);
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. */
/* [temp.friend]
Friend declarations shall not declare partial
specializations. */
- error ("partial specialization `%T' declared `friend'",
+ error ("partial specialization %qT declared %<friend%>",
friend_type);
return;
}
-
- is_template_friend = 1;
}
else if (same_type_p (type, friend_type))
{
if (complain)
- pedwarn ("class `%T' is implicitly friends with itself",
+ pedwarn ("class %qT is implicitly friends with itself",
type);
return;
}
- else
- is_template_friend = 0;
/* [temp.friend]
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 `%#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, class_type, 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);
+ error ("%q+D 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);
+ error ("%q+D declared here", decl);
+ return;
+ }
+
+ friend_type = CLASSTYPE_TI_TEMPLATE (TREE_TYPE (decl));
+ }
+ }
}
else if (TREE_CODE (friend_type) == TEMPLATE_TYPE_PARM)
{
/* template <class T> friend class T; */
- error ("template parameter type `%T' declared `friend'", friend_type);
+ error ("template parameter type %qT declared %<friend%>", friend_type);
return;
}
else if (!CLASSTYPE_TEMPLATE_INFO (friend_type))
{
/* template <class T> friend class A; where A is not a template */
- error ("`%#T' is not a template", friend_type);
+ 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;
if (friend_type == probe)
{
if (complain)
- warning ("`%D' is already a friend of `%T'",
- probe, type);
+ warning (0, "%qD is already a friend of %qT", probe, type);
break;
}
}
if (same_type_p (probe, friend_type))
{
if (complain)
- warning ("`%T' is already a friend of `%T'",
- probe, type);
+ warning (0, "%qT is already a friend of %qT", probe, type);
break;
}
}
}
-
- if (!classes)
+
+ if (!classes)
{
maybe_add_class_template_decl_list (type, friend_type, /*friend_p=*/1);
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)
- = tree_cons (NULL_TREE, type,
- CLASSTYPE_BEFRIENDING_CLASSES (friend_type));
+ = tree_cons (NULL_TREE, type,
+ CLASSTYPE_BEFRIENDING_CLASSES (friend_type));
}
}
-/* Main friend processor.
+/* Main friend processor.
CTYPE is the class this friend belongs to.
tree
do_friend (tree ctype, tree declarator, tree decl,
- tree attrlist, enum overload_flags flags, tree quals,
+ tree attrlist, enum overload_flags flags,
+ cp_cv_quals quals,
int funcdef_flag)
{
/* Every decl that gets here is a friend of something. */
declarator = DECL_NAME (get_first_fn (declarator));
}
- if (TREE_CODE (decl) != FUNCTION_DECL)
- abort ();
+ gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
if (ctype)
{
validity of the declaration later. */
decl = push_template_decl_real (decl, /*is_friend=*/1);
else
- decl = check_classfn (ctype, decl, template_member_p);
+ decl = check_classfn (ctype, decl,
+ template_member_p
+ ? current_template_parms
+ : NULL_TREE);
if (template_member_p && decl && TREE_CODE (decl) == FUNCTION_DECL)
decl = DECL_TI_TEMPLATE (decl);
add_friend (current_class_type, decl, /*complain=*/true);
}
else
- error ("member `%D' declared as friend before type `%T' defined",
+ error ("member %qD declared as friend before type %qT defined",
decl, ctype);
}
/* A global friend.
general, such a declaration depends on template
parameters. Instead, we call pushdecl when the class
is instantiated. */
- decl = push_template_decl_real (decl, /*is_friend=*/1);
+ decl = push_template_decl_real (decl, /*is_friend=*/1);
else if (current_function_decl)
/* This must be a local class, so pushdecl will be ok, and
insert an unqualified friend into the local scope
else
{
/* We can't use pushdecl, as we might be in a template
- class specialization, and pushdecl will insert an
- unqualified friend decl into the template parameter
- scope, rather than the namespace containing it. */
+ class specialization, and pushdecl will insert an
+ unqualified friend decl into the template parameter
+ scope, rather than the namespace containing it. */
tree ns = decl_namespace_context (decl);
-
+
push_nested_namespace (ns);
decl = pushdecl_namespace_level (decl);
pop_nested_namespace (ns);
if (warn)
{
static int explained;
- warning ("friend declaration `%#D' declares a non-template function", decl);
+ warning (0, "friend declaration %q#D declares a non-template "
+ "function", decl);
if (! explained)
{
- warning ("(if this is not what you intended, make sure the function template has already been declared and add <> after the function name here) -Wno-non-template-friend disables this warning");
+ warning (0, "(if this is not what you intended, make sure "
+ "the function template has already been declared "
+ "and add <> after the function name here) "
+ "-Wno-non-template-friend disables this warning");
explained = 1;
}
}
if (decl == error_mark_node)
return error_mark_node;
-
- add_friend (current_class_type,
+
+ add_friend (current_class_type,
is_friend_template ? DECL_TI_TEMPLATE (decl) : decl,
/*complain=*/true);
DECL_FRIEND_P (decl) = 1;