#include "config.h"
#include "system.h"
#include "tree.h"
#include "rtl.h"
#include "cp-tree.h"
#include "flags.h"
#include "output.h"
#include "toplev.h"
int
is_friend (type, supplicant)
tree type, supplicant;
{
int declp;
register tree list;
tree context;
if (supplicant == NULL_TREE || type == NULL_TREE)
return 0;
declp = (TREE_CODE_CLASS (TREE_CODE (supplicant)) == 'd');
if (declp)
{
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 == FRIEND_NAME (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;
if ((flag_guiding_decls
|| DECL_FUNCTION_MEMBER_P (supplicant))
&& same_type_p (TREE_TYPE (supplicant),
TREE_TYPE (TREE_VALUE (friends))))
return 1;
if (TREE_CODE (TREE_VALUE (friends)) == TEMPLATE_DECL
&& is_specialization_of (supplicant,
TREE_VALUE (friends)))
return 1;
}
break;
}
}
}
else
{
if (type == supplicant)
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) :
same_type_p (supplicant, t))
return 1;
}
}
if (declp && DECL_FUNCTION_MEMBER_P (supplicant))
context = DECL_CLASS_CONTEXT (supplicant);
else if (! declp)
context = hack_decl_function_context (TYPE_MAIN_DECL (supplicant));
else
context = NULL_TREE;
if (context && TREE_CODE (context) == NAMESPACE_DECL)
context = NULL_TREE;
if (context)
return is_friend (type, context);
return 0;
}
void
add_friend (type, decl)
tree type, 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 == FRIEND_NAME (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'",
decl, type);
cp_warning_at ("previous friend declaration of `%D'",
TREE_VALUE (friends));
return;
}
}
TREE_VALUE (list) = tree_cons (error_mark_node, decl,
TREE_VALUE (list));
return;
}
list = TREE_CHAIN (list);
}
DECL_FRIENDLIST (typedecl)
= tree_cons (DECL_NAME (decl), build_tree_list (error_mark_node, decl),
DECL_FRIENDLIST (typedecl));
if (!uses_template_parms (type))
DECL_BEFRIENDING_CLASSES (decl)
= tree_cons (NULL_TREE, type,
DECL_BEFRIENDING_CLASSES (decl));
}
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 == FRIEND_NAME (list))
{
tree friends = FRIEND_DECLS (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),
DECL_FRIENDLIST (typedecl));
}
void
make_friend_class (type, friend_type)
tree type, friend_type;
{
tree classes;
int is_template_friend;
if (IS_SIGNATURE (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);
return;
}
if (CLASS_TYPE_P (friend_type)
&& CLASSTYPE_TEMPLATE_SPECIALIZATION (friend_type)
&& uses_template_parms (friend_type))
{
cp_error ("partial specialization `%T' declared `friend'",
friend_type);
return;
}
if (processing_template_decl > template_class_depth (type))
is_template_friend = 1;
else if (same_type_p (type, friend_type))
{
pedwarn ("class `%s' is implicitly friends with itself",
TYPE_NAME_STRING (type));
return;
}
else
is_template_friend = 0;
GNU_xref_hier (type, friend_type, 0, 0, 1);
if (is_template_friend)
friend_type = CLASSTYPE_TI_TEMPLATE (friend_type);
classes = CLASSTYPE_FRIEND_CLASSES (type);
while (classes
&& !(TREE_CODE (TREE_VALUE (classes)) == TEMPLATE_DECL ?
friend_type == TREE_VALUE (classes) :
same_type_p (TREE_VALUE (classes), friend_type)))
classes = TREE_CHAIN (classes);
if (classes)
cp_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));
}
}
tree
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;
{
int is_friend_template = 0;
tree prefix_attributes, attributes;
DECL_FRIEND_P (decl) = 1;
if (TREE_CODE (declarator) == TEMPLATE_ID_EXPR)
{
declarator = TREE_OPERAND (declarator, 0);
if (TREE_CODE (declarator) == LOOKUP_EXPR)
declarator = TREE_OPERAND (declarator, 0);
if (is_overloaded_fn (declarator))
declarator = DECL_NAME (get_first_fn (declarator));
}
if (TREE_CODE (decl) != FUNCTION_DECL)
my_friendly_abort (990513);
if (flag_dump_symbols)
printf ("+fh %s %u\n", IDENTIFIER_POINTER (DECL_NAME (decl)),
DECL_SOURCE_LINE (decl));
if (flag_gen_index)
dump_symbol_info ("+fh ", IDENTIFIER_POINTER (DECL_NAME (decl)),
DECL_SOURCE_LINE (decl));
is_friend_template = PROCESSING_REAL_TEMPLATE_DECL_P ();
if (ctype)
{
tree cname = TYPE_NAME (ctype);
if (TREE_CODE (cname) == TYPE_DECL)
cname = DECL_NAME (cname);
if (flags == NO_SPECIAL && ctype && declarator == cname)
DECL_CONSTRUCTOR_P (decl) = 1;
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, 1);
if (uses_template_parms (ctype))
add_friend (current_class_type, decl);
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 if (TREE_CODE (decl) == FUNCTION_DECL)
{
DECL_ARGUMENTS (decl) = parmdecls;
if (funcdef_flag)
DECL_CLASS_CONTEXT (decl) = current_class_type;
if (! DECL_USE_TEMPLATE (decl))
{
if (!is_friend_template
&& template_class_depth (current_class_type) == 0)
decl = pushdecl (decl);
else
decl = push_template_decl_real (decl, 1);
if (warn_nontemplate_friend
&& ! funcdef_flag && ! flag_guiding_decls && ! is_friend_template
&& current_template_parms && uses_template_parms (decl))
{
static int explained;
cp_warning ("friend declaration `%#D'", decl);
warning (" declares a non-template function");
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.");
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;
}
if (attrlist)
{
attributes = TREE_PURPOSE (attrlist);
prefix_attributes = TREE_VALUE (attrlist);
}
else
{
attributes = NULL_TREE;
prefix_attributes = NULL_TREE;
}
#ifdef SET_DEFAULT_DECL_ATTRIBUTES
SET_DEFAULT_DECL_ATTRIBUTES (decl, attributes);
#endif
cplus_decl_attributes (decl, attributes, prefix_attributes);
return decl;
}