/* Help friends in C++.
- Copyright (C) 1997, 1998, 1999 Free Software Foundation, Inc.
+ Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
This file is part of GNU CC.
#include "system.h"
#include "tree.h"
#include "rtl.h"
+#include "expr.h"
#include "cp-tree.h"
#include "flags.h"
#include "output.h"
#include "toplev.h"
-static void add_friend PROTO((tree, tree));
-static void add_friends PROTO((tree, tree, tree));
-
/* Friend data structures are described in cp-tree.h. */
/* Returns non-zero if SUPPLICANT is a friend of TYPE. */
if (supplicant == NULL_TREE || type == NULL_TREE)
return 0;
- declp = (TREE_CODE_CLASS (TREE_CODE (supplicant)) == 'd');
+ declp = DECL_P (supplicant);
if (declp)
/* It's a function decl. */
{
tree list = DECL_FRIENDLIST (TYPE_MAIN_DECL (type));
tree name = DECL_NAME (supplicant);
- tree ctype;
-
- if (DECL_FUNCTION_MEMBER_P (supplicant))
- ctype = DECL_CLASS_CONTEXT (supplicant);
- else
- ctype = NULL_TREE;
for (; list ; list = TREE_CHAIN (list))
{
- if (name == TREE_PURPOSE (list))
+ if (name == FRIEND_NAME (list))
{
- tree friends = TREE_VALUE (list);
+ tree friends = FRIEND_DECLS (list);
for (; friends ; friends = TREE_CHAIN (friends))
{
- if (same_type_p (ctype, TREE_PURPOSE (friends)))
- return 1;
-
if (TREE_VALUE (friends) == NULL_TREE)
continue;
if (supplicant == TREE_VALUE (friends))
return 1;
- /* With -fguiding-decls we are more lenient about
- friendship. This is bogus in general since two
- specializations of a template with non-type
- template parameters may have the same type, but
- be different.
-
- Temporarily, we are also 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, the
- FUNCTION_MEMBER_P bit can go. */
- if ((flag_guiding_decls
- || DECL_FUNCTION_MEMBER_P (supplicant))
+ /* 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))))
return 1;
else
/* It's a type. */
{
- if (type == supplicant)
- return 1;
+ /* Nested classes are implicitly friends of their enclosing types, as
+ per core issue 45 (this is a change from the standard). */
+ for (context = supplicant;
+ context && TYPE_P (context);
+ 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))
}
if (declp && DECL_FUNCTION_MEMBER_P (supplicant))
- context = DECL_CLASS_CONTEXT (supplicant);
+ context = DECL_CONTEXT (supplicant);
else if (! declp)
/* Local classes have the same access as the enclosing function. */
- context = hack_decl_function_context (TYPE_MAIN_DECL (supplicant));
+ context = decl_function_context (TYPE_MAIN_DECL (supplicant));
else
context = NULL_TREE;
/* Add a new friend to the friends of the aggregate type TYPE.
DECL is the FUNCTION_DECL of the friend being added. */
-static void
+void
add_friend (type, decl)
tree type, decl;
{
- tree typedecl = TYPE_MAIN_DECL (type);
- tree list = DECL_FRIENDLIST (typedecl);
- tree name = DECL_NAME (decl);
+ tree typedecl;
+ tree list;
+ tree name;
+
+ if (decl == error_mark_node)
+ return;
+
+ typedecl = TYPE_MAIN_DECL (type);
+ list = DECL_FRIENDLIST (typedecl);
+ name = DECL_NAME (decl);
+ type = TREE_TYPE (typedecl);
while (list)
{
- if (name == TREE_PURPOSE (list))
+ if (name == FRIEND_NAME (list))
{
- tree friends = TREE_VALUE (list);
+ tree friends = FRIEND_DECLS (list);
for (; friends ; friends = TREE_CHAIN (friends))
{
if (decl == TREE_VALUE (friends))
{
- cp_warning ("`%D' is already a friend of class `%T'",
+ warning ("`%D' is already a friend of class `%T'",
decl, type);
cp_warning_at ("previous friend declaration of `%D'",
TREE_VALUE (friends));
}
list = TREE_CHAIN (list);
}
- DECL_FRIENDLIST (typedecl)
- = tree_cons (DECL_NAME (decl), build_tree_list (error_mark_node, decl),
- DECL_FRIENDLIST (typedecl));
- if (DECL_NAME (decl) == ansi_opname[(int) MODIFY_EXPR])
- {
- tree parmtypes = TYPE_ARG_TYPES (TREE_TYPE (decl));
- TYPE_HAS_ASSIGNMENT (TREE_TYPE (typedecl)) = 1;
- if (parmtypes && TREE_CHAIN (parmtypes))
- {
- tree parmtype = TREE_VALUE (TREE_CHAIN (parmtypes));
- if (TREE_CODE (parmtype) == REFERENCE_TYPE
- && TREE_TYPE (parmtypes) == TREE_TYPE (typedecl))
- TYPE_HAS_ASSIGN_REF (TREE_TYPE (typedecl)) = 1;
- }
- }
-}
-
-/* Declare that every member function NAME in FRIEND_TYPE
- (which may be NULL_TREE) is a friend of type TYPE. */
-
-static void
-add_friends (type, name, friend_type)
- tree type, name, friend_type;
-{
- tree typedecl = TYPE_MAIN_DECL (type);
- tree list = DECL_FRIENDLIST (typedecl);
- while (list)
- {
- if (name == TREE_PURPOSE (list))
- {
- tree friends = TREE_VALUE (list);
- while (friends && TREE_PURPOSE (friends) != friend_type)
- friends = TREE_CHAIN (friends);
- if (friends)
- {
- if (friend_type)
- warning ("method `%s::%s' is already a friend of class",
- TYPE_NAME_STRING (friend_type),
- IDENTIFIER_POINTER (name));
- else
- warning ("function `%s' is already a friend of class `%s'",
- IDENTIFIER_POINTER (name),
- IDENTIFIER_POINTER (DECL_NAME (typedecl)));
- }
- else
- TREE_VALUE (list) = tree_cons (friend_type, NULL_TREE,
- TREE_VALUE (list));
- return;
- }
- list = TREE_CHAIN (list);
- }
DECL_FRIENDLIST (typedecl)
- = tree_cons (name,
- build_tree_list (friend_type, NULL_TREE),
+ = tree_cons (DECL_NAME (decl), build_tree_list (error_mark_node, decl),
DECL_FRIENDLIST (typedecl));
- if (! strncmp (IDENTIFIER_POINTER (name),
- IDENTIFIER_POINTER (ansi_opname[(int) MODIFY_EXPR]),
- strlen (IDENTIFIER_POINTER (ansi_opname[(int) MODIFY_EXPR]))))
- {
- TYPE_HAS_ASSIGNMENT (TREE_TYPE (typedecl)) = 1;
- sorry ("declaring \"friend operator =\" will not find \"operator = (X&)\" if it exists");
- }
+ if (!uses_template_parms (type))
+ DECL_BEFRIENDING_CLASSES (decl)
+ = tree_cons (NULL_TREE, type,
+ DECL_BEFRIENDING_CLASSES (decl));
}
/* Make FRIEND_TYPE a friend class to TYPE. If FRIEND_TYPE has already
tree classes;
int is_template_friend;
- if (IS_SIGNATURE (type))
+ if (! IS_AGGR_TYPE (friend_type))
{
- error ("`friend' declaration in signature definition");
- return;
- }
- if (IS_SIGNATURE (friend_type) || ! IS_AGGR_TYPE (friend_type))
- {
- cp_error ("invalid type `%T' declared `friend'", friend_type);
+ error ("invalid type `%T' declared `friend'", friend_type);
return;
}
- if (CLASSTYPE_TEMPLATE_SPECIALIZATION (friend_type)
+ if (CLASS_TYPE_P (friend_type)
+ && CLASSTYPE_TEMPLATE_SPECIALIZATION (friend_type)
&& uses_template_parms (friend_type))
{
/* [temp.friend]
Friend declarations shall not declare partial
specializations. */
- cp_error ("partial specialization `%T' declared `friend'",
+ error ("partial specialization `%T' declared `friend'",
friend_type);
return;
}
-
+
if (processing_template_decl > template_class_depth (type))
/* If the TYPE is a template then it makes sense for it to be
friends with itself; this means that each instantiation is
is_template_friend = 1;
else if (same_type_p (type, friend_type))
{
- pedwarn ("class `%s' is implicitly friends with itself",
- TYPE_NAME_STRING (type));
+ pedwarn ("class `%T' is implicitly friends with itself",
+ type);
return;
}
else
is_template_friend = 0;
- GNU_xref_hier (type, friend_type, 0, 0, 1);
+ /* [temp.friend]
+
+ A friend of a class or class template can be a function or
+ class template, a specialization of a function template or
+ class template, or an ordinary (nontemplate) function or
+ class. */
+ if (!is_template_friend)
+ ;/* 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;
+ }
+ else if (TREE_CODE (friend_type) == TEMPLATE_TYPE_PARM)
+ {
+ /* template <class T> friend class T; */
+ error ("template parameter type `%T' 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);
+ return;
+ }
if (is_template_friend)
friend_type = CLASSTYPE_TI_TEMPLATE (friend_type);
same_type_p (TREE_VALUE (classes), friend_type)))
classes = TREE_CHAIN (classes);
if (classes)
- cp_warning ("`%T' is already a friend of `%T'",
+ warning ("`%T' is already a friend of `%T'",
TREE_VALUE (classes), type);
else
{
CLASSTYPE_FRIEND_CLASSES (type)
= tree_cons (NULL_TREE, friend_type, CLASSTYPE_FRIEND_CLASSES (type));
+ if (is_template_friend)
+ 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));
}
}
pointed to by `this'. */
tree
-do_friend (ctype, declarator, decl, parmdecls, flags, quals, funcdef_flag)
- tree ctype, declarator, decl, parmdecls;
+do_friend (ctype, declarator, decl, parmdecls, attrlist,
+ flags, quals, funcdef_flag)
+ tree ctype, declarator, decl, parmdecls, attrlist;
enum overload_flags flags;
tree quals;
int funcdef_flag;
declarator = DECL_NAME (get_first_fn (declarator));
}
- if (TREE_CODE (decl) == FUNCTION_DECL)
- is_friend_template = PROCESSING_REAL_TEMPLATE_DECL_P ();
+ if (TREE_CODE (decl) != FUNCTION_DECL)
+ abort ();
+
+ is_friend_template = PROCESSING_REAL_TEMPLATE_DECL_P ();
if (ctype)
{
cname = DECL_NAME (cname);
/* A method friend. */
- if (TREE_CODE (decl) == FUNCTION_DECL)
+ if (flags == NO_SPECIAL && ctype && 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 (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);
+ /* 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 (flags == NO_SPECIAL && ctype && declarator == cname)
- DECL_CONSTRUCTOR_P (decl) = 1;
-
- /* This will set up DECL_ARGUMENTS for us. */
- grokclassfn (ctype, decl, flags, quals);
+ decl = check_classfn (ctype, decl);
- if (is_friend_template)
- decl = DECL_TI_TEMPLATE (push_template_decl (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 (uses_template_parms (ctype))
+ if (decl)
add_friend (current_class_type, decl);
- /* 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 (TYPE_SIZE (ctype) != 0 || TYPE_BEING_DEFINED (ctype))
- {
- decl = check_classfn (ctype, decl);
-
- if (decl)
- add_friend (current_class_type, decl);
- }
- else
- cp_error ("member `%D' declared as friend before type `%T' defined",
- decl, ctype);
}
else
- {
- /* Possibly a bunch of method friends. */
-
- /* Get the class they belong to. */
- tree ctype = IDENTIFIER_TYPE_VALUE (cname);
- tree fields = lookup_fnfields (TYPE_BINFO (ctype), declarator, 0);
-
- if (fields)
- add_friends (current_class_type, declarator, ctype);
- else
- cp_error ("method `%D' is not a member of class `%T'",
- declarator, ctype);
- decl = void_type_node;
- }
+ error ("member `%D' declared as friend before type `%T' defined",
+ decl, ctype);
}
/* A global friend.
@@ or possibly a friend from a base class ?!? */
in their scope, their friend wind up in top-level scope as well. */
DECL_ARGUMENTS (decl) = parmdecls;
if (funcdef_flag)
- DECL_CLASS_CONTEXT (decl) = current_class_type;
+ SET_DECL_FRIEND_CONTEXT (decl, current_class_type);
if (! DECL_USE_TEMPLATE (decl))
{
- /* We can call pushdecl here, because the TREE_CHAIN of this
- FUNCTION_DECL is not needed for other purposes. Don't do
- this for a template instantiation. However, we don't
- call pushdecl() for a friend function of a template
- class, since in general, such a declaration depends on
- template parameters. Instead, we call pushdecl when the
- class is instantiated. */
- if (!is_friend_template
- && template_class_depth (current_class_type) == 0)
- decl = pushdecl (decl);
- else
+ /* We must check whether the decl refers to template
+ arguments before push_template_decl_real adds a
+ reference to the containing template class. */
+ int warn = (warn_nontemplate_friend
+ && ! funcdef_flag && ! is_friend_template
+ && current_template_parms
+ && uses_template_parms (decl));
+
+ if (is_friend_template
+ || template_class_depth (current_class_type) != 0)
+ /* We can't call pushdecl for a template class, since in
+ 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);
+ 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
+ (rather than the containing namespace scope, which the
+ next choice will do). */
+ decl = pushdecl (decl);
+ 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. */
+ tree ns = decl_namespace_context (decl);
+
+ push_nested_namespace (ns);
+ decl = pushdecl_namespace_level (decl);
+ pop_nested_namespace (ns);
+ }
- if (warn_nontemplate_friend
- && ! funcdef_flag && ! flag_guiding_decls && ! is_friend_template
- && current_template_parms && uses_template_parms (decl))
+ if (warn)
{
static int explained;
- cp_warning ("friend declaration `%#D'", decl);
- warning (" declares a non-template function");
+ warning ("friend declaration `%#D' declares a non-template function", decl);
if (! explained)
{
- warning (" (if this is not what you intended, make sure");
- warning (" the function template has already been declared,");
- warning (" and add <> after the function name here)");
- warning (" -Wno-non-template-friend disables this warning.");
+ 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");
explained = 1;
}
}
}
- make_decl_rtl (decl, NULL_PTR, 1);
add_friend (current_class_type,
is_friend_template ? DECL_TI_TEMPLATE (decl) : decl);
DECL_FRIEND_P (decl) = 1;
}
- else
- {
- /* @@ Should be able to ingest later definitions of this function
- before use. */
- tree decl = lookup_name_nonclass (declarator);
- if (decl == NULL_TREE)
- {
- cp_warning ("implicitly declaring `%T' as struct", declarator);
- decl = xref_tag (record_type_node, declarator, 1);
- decl = TYPE_MAIN_DECL (decl);
- }
- /* Allow abbreviated declarations of overloaded functions,
- but not if those functions are really class names. */
- if (TREE_CODE (decl) == TREE_LIST && TREE_TYPE (TREE_PURPOSE (decl)))
- {
- cp_warning ("`friend %T' archaic, use `friend class %T' instead",
- declarator, declarator);
- decl = TREE_TYPE (TREE_PURPOSE (decl));
- }
+ /* Unfortunately, we have to handle attributes here. Normally we would
+ handle them in start_decl_1, but since this is a friend decl start_decl_1
+ never gets to see it. */
+
+ /* Set attributes here so if duplicate decl, will have proper attributes. */
+ cplus_decl_attributes (&decl, attrlist, 0);
- if (TREE_CODE (decl) == TREE_LIST)
- add_friends (current_class_type, TREE_PURPOSE (decl), NULL_TREE);
- else
- make_friend_class (current_class_type, TREE_TYPE (decl));
- decl = void_type_node;
- }
return decl;
}