diff options
author | Marc Espie <espie@cvs.openbsd.org> | 1999-05-26 13:38:57 +0000 |
---|---|---|
committer | Marc Espie <espie@cvs.openbsd.org> | 1999-05-26 13:38:57 +0000 |
commit | 0126e157b87f137fc08dc7f46f6c291b9d06ac5d (patch) | |
tree | f8555e3e504eb82b4cd3cba5cec20ae4ce8124ff /gnu/egcs/gcc/cp/friend.c | |
parent | ff8e9a4356e55ed142306c3a375fa280800abc86 (diff) |
egcs projects compiler system
Exact copy of the snapshot, except for the removal of
texinfo/
gcc/ch/
libchill/
Diffstat (limited to 'gnu/egcs/gcc/cp/friend.c')
-rw-r--r-- | gnu/egcs/gcc/cp/friend.c | 472 |
1 files changed, 472 insertions, 0 deletions
diff --git a/gnu/egcs/gcc/cp/friend.c b/gnu/egcs/gcc/cp/friend.c new file mode 100644 index 00000000000..5085ebc7747 --- /dev/null +++ b/gnu/egcs/gcc/cp/friend.c @@ -0,0 +1,472 @@ +/* Help friends in C++. + Copyright (C) 1997, 1998, 1999 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU CC is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU CC; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#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" + +/* Friend data structures are described in cp-tree.h. */ + +/* Returns non-zero if SUPPLICANT is a friend of TYPE. */ + +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) + /* 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 == 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; + + /* 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)) + && 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 + /* It's a type. */ + { + 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) + /* Local classes have the same access as the enclosing function. */ + context = hack_decl_function_context (TYPE_MAIN_DECL (supplicant)); + else + context = NULL_TREE; + + /* A namespace is not friend to anybody. */ + if (context && TREE_CODE (context) == NAMESPACE_DECL) + context = NULL_TREE; + + if (context) + return is_friend (type, context); + + return 0; +} + +/* Add a new friend to the friends of the aggregate type TYPE. + DECL is the FUNCTION_DECL of the friend being added. */ + +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)); +} + +/* Declare that every member function NAME in FRIEND_TYPE + (which may be NULL_TREE) is a friend of type TYPE. */ + +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)); +} + +/* Make FRIEND_TYPE a friend class to TYPE. If FRIEND_TYPE has already + been defined, we make all of its member functions friends of + TYPE. If not, we make it a pending friend, which can later be added + when its definition is seen. If a type is defined, then its TYPE_DECL's + DECL_UNDEFINED_FRIENDS contains a (possibly empty) list of friend + classes that are not defined. If a type has not yet been defined, + then the DECL_WAITING_FRIENDS contains a list of types + waiting to make it their friend. Note that these two can both + be in use at the same time! */ + +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)) + { + /* [temp.friend] + + Friend declarations shall not declare partial + specializations. */ + cp_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 + friends with all other instantiations. */ + 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 + /* Stop if we find the same type on the list. */ + && !(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)); + } +} + +/* Main friend processor. This is large, and for modularity purposes, + has been removed from grokdeclarator. It returns `void_type_node' + to indicate that something happened, though a FIELD_DECL is + not returned. + + CTYPE is the class this friend belongs to. + + DECLARATOR is the name of the friend. + + DECL is the FUNCTION_DECL that the friend is. + + In case we are parsing a friend which is part of an inline + definition, we will need to store PARM_DECL chain that comes + with it into the DECL_ARGUMENTS slot of the FUNCTION_DECL. + + FLAGS is just used for `grokclassfn'. + + QUALS say what special qualifies should apply to the object + pointed to by `this'. */ + +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; + + /* Every decl that gets here is a friend of something. */ + 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); + + 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); + + /* A method friend. */ + 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 (uses_template_parms (ctype)) + 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); + } + /* A global friend. + @@ or possibly a friend from a base class ?!? */ + else if (TREE_CODE (decl) == FUNCTION_DECL) + { + /* Friends must all go through the overload machinery, + even though they may not technically be overloaded. + + Note that because classes all wind up being top-level + 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; + + 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 + decl = push_template_decl_real (decl, /*is_friend=*/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; + } + + /* 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. */ + + 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 + + /* Set attributes here so if duplicate decl, will have proper attributes. */ + cplus_decl_attributes (decl, attributes, prefix_attributes); + + return decl; +} |