#include "config.h"
#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"
#include "genindex.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 = DECL_P (supplicant);
if (declp)
{
tree list = DECL_FRIENDLIST (TYPE_MAIN_DECL (type));
tree name = DECL_NAME (supplicant);
for (; list ; list = TREE_CHAIN (list))
{
if (name == FRIEND_NAME (list))
{
tree friends = FRIEND_DECLS (list);
for (; friends ; friends = TREE_CHAIN (friends))
{
if (TREE_VALUE (friends) == NULL_TREE)
continue;
if (supplicant == TREE_VALUE (friends))
return 1;
if (TREE_CODE (supplicant) == TEMPLATE_DECL)
return 1;
if (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
{
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))
{
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_CONTEXT (supplicant);
else if (! declp)
context = 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))
{
warning ("`%D' is already a friend of class `%T'",
decl, type);
cp_warning_at ("previous friend declaration of `%D'",
TREE_VALUE (friends));
return;
}
}
maybe_add_class_template_decl_list (type, decl, 1);
TREE_VALUE (list) = tree_cons (error_mark_node, decl,
TREE_VALUE (list));
return;
}
list = TREE_CHAIN (list);
}
maybe_add_class_template_decl_list (type, decl, 1);
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
make_friend_class (type, friend_type)
tree type, friend_type;
{
tree classes;
int is_template_friend;
if (! IS_AGGR_TYPE (friend_type))
{
error ("invalid type `%T' declared `friend'", friend_type);
return;
}
if (processing_template_decl > template_class_depth (type))
{
if (CLASS_TYPE_P (friend_type)
&& CLASSTYPE_TEMPLATE_SPECIALIZATION (friend_type)
&& uses_template_parms (friend_type))
{
error ("partial specialization `%T' declared `friend'",
friend_type);
return;
}
is_template_friend = 1;
}
else if (same_type_p (type, friend_type))
{
pedwarn ("class `%T' is implicitly friends with itself",
type);
return;
}
else
is_template_friend = 0;
if (!is_template_friend)
;
else if (TREE_CODE (friend_type) == TYPENAME_TYPE)
{
error ("typename type `%#T' declared `friend'", friend_type);
return;
}
else if (TREE_CODE (friend_type) == TEMPLATE_TYPE_PARM)
{
error ("template parameter type `%T' declared `friend'", friend_type);
return;
}
else if (!CLASSTYPE_TEMPLATE_INFO (friend_type))
{
error ("`%#T' is not a template", friend_type);
return;
}
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)
warning ("`%T' is already a friend of `%T'",
TREE_VALUE (classes), type);
else
{
maybe_add_class_template_decl_list (type, friend_type, 1);
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;
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)
abort ();
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 (processing_template_decl)
add_friend (current_class_type, decl);
else if (COMPLETE_TYPE_P (ctype) || TYPE_BEING_DEFINED (ctype))
{
decl = check_classfn (ctype, decl);
if (decl)
add_friend (current_class_type, decl);
}
else
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)
SET_DECL_FRIEND_CONTEXT (decl, current_class_type);
if (! DECL_USE_TEMPLATE (decl))
{
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)
decl = push_template_decl_real (decl, 1);
else if (current_function_decl)
decl = pushdecl (decl);
else
{
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);
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");
explained = 1;
}
}
}
add_friend (current_class_type,
is_friend_template ? DECL_TI_TEMPLATE (decl) : decl);
DECL_FRIEND_P (decl) = 1;
}
cplus_decl_attributes (&decl, attrlist, 0);
if (flag_gen_index)
gen_indexing_info (INDEX_FUNCTION_DECL,
IDENTIFIER_POINTER (DECL_NAME (decl)),
DECL_SOURCE_LINE (decl));
return decl;
}