friend.c revision 50397
150397Sobrien/* Help friends in C++. 250397Sobrien Copyright (C) 1997 Free Software Foundation, Inc. 350397Sobrien 450397SobrienThis file is part of GNU CC. 550397Sobrien 650397SobrienGNU CC is free software; you can redistribute it and/or modify 750397Sobrienit under the terms of the GNU General Public License as published by 850397Sobrienthe Free Software Foundation; either version 2, or (at your option) 950397Sobrienany later version. 1050397Sobrien 1150397SobrienGNU CC is distributed in the hope that it will be useful, 1250397Sobrienbut WITHOUT ANY WARRANTY; without even the implied warranty of 1350397SobrienMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1450397SobrienGNU General Public License for more details. 1550397Sobrien 1650397SobrienYou should have received a copy of the GNU General Public License 1750397Sobrienalong with GNU CC; see the file COPYING. If not, write to 1850397Sobrienthe Free Software Foundation, 59 Temple Place - Suite 330, 1950397SobrienBoston, MA 02111-1307, USA. */ 2050397Sobrien 2150397Sobrien#include "config.h" 2250397Sobrien#include "system.h" 2350397Sobrien#include "tree.h" 2450397Sobrien#include "rtl.h" 2550397Sobrien#include "cp-tree.h" 2650397Sobrien#include "flags.h" 2750397Sobrien#include "output.h" 2850397Sobrien#include "toplev.h" 2950397Sobrien 3050397Sobrienstatic void add_friend PROTO((tree, tree)); 3150397Sobrienstatic void add_friends PROTO((tree, tree, tree)); 3250397Sobrien 3350397Sobrien/* Friend data structures are described in cp-tree.h. */ 3450397Sobrien 3550397Sobrienint 3650397Sobrienis_friend (type, supplicant) 3750397Sobrien tree type, supplicant; 3850397Sobrien{ 3950397Sobrien int declp; 4050397Sobrien register tree list; 4150397Sobrien tree context; 4250397Sobrien 4350397Sobrien if (supplicant == NULL_TREE || type == NULL_TREE) 4450397Sobrien return 0; 4550397Sobrien 4650397Sobrien declp = (TREE_CODE_CLASS (TREE_CODE (supplicant)) == 'd'); 4750397Sobrien 4850397Sobrien if (declp) 4950397Sobrien /* It's a function decl. */ 5050397Sobrien { 5150397Sobrien tree list = DECL_FRIENDLIST (TYPE_MAIN_DECL (type)); 5250397Sobrien tree name = DECL_NAME (supplicant); 5350397Sobrien tree ctype; 5450397Sobrien 5550397Sobrien if (DECL_FUNCTION_MEMBER_P (supplicant)) 5650397Sobrien ctype = DECL_CLASS_CONTEXT (supplicant); 5750397Sobrien else 5850397Sobrien ctype = NULL_TREE; 5950397Sobrien 6050397Sobrien for (; list ; list = TREE_CHAIN (list)) 6150397Sobrien { 6250397Sobrien if (name == TREE_PURPOSE (list)) 6350397Sobrien { 6450397Sobrien tree friends = TREE_VALUE (list); 6550397Sobrien for (; friends ; friends = TREE_CHAIN (friends)) 6650397Sobrien { 6750397Sobrien if (comptypes (ctype, TREE_PURPOSE (friends), 1)) 6850397Sobrien return 1; 6950397Sobrien 7050397Sobrien if (TREE_VALUE (friends) == NULL_TREE) 7150397Sobrien continue; 7250397Sobrien 7350397Sobrien if (TREE_CODE (TREE_VALUE (friends)) == TEMPLATE_DECL) 7450397Sobrien { 7550397Sobrien if (is_specialization_of (supplicant, 7650397Sobrien TREE_VALUE (friends))) 7750397Sobrien return 1; 7850397Sobrien 7950397Sobrien continue; 8050397Sobrien } 8150397Sobrien 8250397Sobrien /* FIXME: The use of comptypes here is bogus, since 8350397Sobrien two specializations of a template with non-type 8450397Sobrien parameters may have the same type, but be 8550397Sobrien different. */ 8650397Sobrien if (comptypes (TREE_TYPE (supplicant), 8750397Sobrien TREE_TYPE (TREE_VALUE (friends)), 1)) 8850397Sobrien return 1; 8950397Sobrien } 9050397Sobrien break; 9150397Sobrien } 9250397Sobrien } 9350397Sobrien } 9450397Sobrien else 9550397Sobrien /* It's a type. */ 9650397Sobrien { 9750397Sobrien if (type == supplicant) 9850397Sobrien return 1; 9950397Sobrien 10050397Sobrien list = CLASSTYPE_FRIEND_CLASSES (TREE_TYPE (TYPE_MAIN_DECL (type))); 10150397Sobrien for (; list ; list = TREE_CHAIN (list)) 10250397Sobrien { 10350397Sobrien tree t = TREE_VALUE (list); 10450397Sobrien 10550397Sobrien if (TREE_CODE (t) == TEMPLATE_DECL ? 10650397Sobrien is_specialization_of (TYPE_MAIN_DECL (supplicant), t) : 10750397Sobrien comptypes (supplicant, t, 1)) 10850397Sobrien return 1; 10950397Sobrien } 11050397Sobrien } 11150397Sobrien 11250397Sobrien if (declp && DECL_FUNCTION_MEMBER_P (supplicant)) 11350397Sobrien context = DECL_CLASS_CONTEXT (supplicant); 11450397Sobrien else if (! declp) 11550397Sobrien /* Local classes have the same access as the enclosing function. */ 11650397Sobrien context = hack_decl_function_context (TYPE_MAIN_DECL (supplicant)); 11750397Sobrien else 11850397Sobrien context = NULL_TREE; 11950397Sobrien 12050397Sobrien /* A namespace is not friend to anybody. */ 12150397Sobrien if (context && TREE_CODE (context) == NAMESPACE_DECL) 12250397Sobrien context = NULL_TREE; 12350397Sobrien 12450397Sobrien if (context) 12550397Sobrien return is_friend (type, context); 12650397Sobrien 12750397Sobrien return 0; 12850397Sobrien} 12950397Sobrien 13050397Sobrien/* Add a new friend to the friends of the aggregate type TYPE. 13150397Sobrien DECL is the FUNCTION_DECL of the friend being added. */ 13250397Sobrien 13350397Sobrienstatic void 13450397Sobrienadd_friend (type, decl) 13550397Sobrien tree type, decl; 13650397Sobrien{ 13750397Sobrien tree typedecl = TYPE_MAIN_DECL (type); 13850397Sobrien tree list = DECL_FRIENDLIST (typedecl); 13950397Sobrien tree name = DECL_NAME (decl); 14050397Sobrien 14150397Sobrien while (list) 14250397Sobrien { 14350397Sobrien if (name == TREE_PURPOSE (list)) 14450397Sobrien { 14550397Sobrien tree friends = TREE_VALUE (list); 14650397Sobrien for (; friends ; friends = TREE_CHAIN (friends)) 14750397Sobrien { 14850397Sobrien if (decl == TREE_VALUE (friends)) 14950397Sobrien { 15050397Sobrien cp_warning ("`%D' is already a friend of class `%T'", 15150397Sobrien decl, type); 15250397Sobrien cp_warning_at ("previous friend declaration of `%D'", 15350397Sobrien TREE_VALUE (friends)); 15450397Sobrien return; 15550397Sobrien } 15650397Sobrien } 15750397Sobrien TREE_VALUE (list) = tree_cons (error_mark_node, decl, 15850397Sobrien TREE_VALUE (list)); 15950397Sobrien return; 16050397Sobrien } 16150397Sobrien list = TREE_CHAIN (list); 16250397Sobrien } 16350397Sobrien DECL_FRIENDLIST (typedecl) 16450397Sobrien = tree_cons (DECL_NAME (decl), build_tree_list (error_mark_node, decl), 16550397Sobrien DECL_FRIENDLIST (typedecl)); 16650397Sobrien if (DECL_NAME (decl) == ansi_opname[(int) MODIFY_EXPR]) 16750397Sobrien { 16850397Sobrien tree parmtypes = TYPE_ARG_TYPES (TREE_TYPE (decl)); 16950397Sobrien TYPE_HAS_ASSIGNMENT (TREE_TYPE (typedecl)) = 1; 17050397Sobrien if (parmtypes && TREE_CHAIN (parmtypes)) 17150397Sobrien { 17250397Sobrien tree parmtype = TREE_VALUE (TREE_CHAIN (parmtypes)); 17350397Sobrien if (TREE_CODE (parmtype) == REFERENCE_TYPE 17450397Sobrien && TREE_TYPE (parmtypes) == TREE_TYPE (typedecl)) 17550397Sobrien TYPE_HAS_ASSIGN_REF (TREE_TYPE (typedecl)) = 1; 17650397Sobrien } 17750397Sobrien } 17850397Sobrien} 17950397Sobrien 18050397Sobrien/* Declare that every member function NAME in FRIEND_TYPE 18150397Sobrien (which may be NULL_TREE) is a friend of type TYPE. */ 18250397Sobrien 18350397Sobrienstatic void 18450397Sobrienadd_friends (type, name, friend_type) 18550397Sobrien tree type, name, friend_type; 18650397Sobrien{ 18750397Sobrien tree typedecl = TYPE_MAIN_DECL (type); 18850397Sobrien tree list = DECL_FRIENDLIST (typedecl); 18950397Sobrien 19050397Sobrien while (list) 19150397Sobrien { 19250397Sobrien if (name == TREE_PURPOSE (list)) 19350397Sobrien { 19450397Sobrien tree friends = TREE_VALUE (list); 19550397Sobrien while (friends && TREE_PURPOSE (friends) != friend_type) 19650397Sobrien friends = TREE_CHAIN (friends); 19750397Sobrien if (friends) 19850397Sobrien { 19950397Sobrien if (friend_type) 20050397Sobrien warning ("method `%s::%s' is already a friend of class", 20150397Sobrien TYPE_NAME_STRING (friend_type), 20250397Sobrien IDENTIFIER_POINTER (name)); 20350397Sobrien else 20450397Sobrien warning ("function `%s' is already a friend of class `%s'", 20550397Sobrien IDENTIFIER_POINTER (name), 20650397Sobrien IDENTIFIER_POINTER (DECL_NAME (typedecl))); 20750397Sobrien } 20850397Sobrien else 20950397Sobrien TREE_VALUE (list) = tree_cons (friend_type, NULL_TREE, 21050397Sobrien TREE_VALUE (list)); 21150397Sobrien return; 21250397Sobrien } 21350397Sobrien list = TREE_CHAIN (list); 21450397Sobrien } 21550397Sobrien DECL_FRIENDLIST (typedecl) 21650397Sobrien = tree_cons (name, 21750397Sobrien build_tree_list (friend_type, NULL_TREE), 21850397Sobrien DECL_FRIENDLIST (typedecl)); 21950397Sobrien if (! strncmp (IDENTIFIER_POINTER (name), 22050397Sobrien IDENTIFIER_POINTER (ansi_opname[(int) MODIFY_EXPR]), 22150397Sobrien strlen (IDENTIFIER_POINTER (ansi_opname[(int) MODIFY_EXPR])))) 22250397Sobrien { 22350397Sobrien TYPE_HAS_ASSIGNMENT (TREE_TYPE (typedecl)) = 1; 22450397Sobrien sorry ("declaring \"friend operator =\" will not find \"operator = (X&)\" if it exists"); 22550397Sobrien } 22650397Sobrien} 22750397Sobrien 22850397Sobrien/* Make FRIEND_TYPE a friend class to TYPE. If FRIEND_TYPE has already 22950397Sobrien been defined, we make all of its member functions friends of 23050397Sobrien TYPE. If not, we make it a pending friend, which can later be added 23150397Sobrien when its definition is seen. If a type is defined, then its TYPE_DECL's 23250397Sobrien DECL_UNDEFINED_FRIENDS contains a (possibly empty) list of friend 23350397Sobrien classes that are not defined. If a type has not yet been defined, 23450397Sobrien then the DECL_WAITING_FRIENDS contains a list of types 23550397Sobrien waiting to make it their friend. Note that these two can both 23650397Sobrien be in use at the same time! */ 23750397Sobrien 23850397Sobrienvoid 23950397Sobrienmake_friend_class (type, friend_type) 24050397Sobrien tree type, friend_type; 24150397Sobrien{ 24250397Sobrien tree classes; 24350397Sobrien int is_template_friend; 24450397Sobrien 24550397Sobrien if (IS_SIGNATURE (type)) 24650397Sobrien { 24750397Sobrien error ("`friend' declaration in signature definition"); 24850397Sobrien return; 24950397Sobrien } 25050397Sobrien if (IS_SIGNATURE (friend_type)) 25150397Sobrien { 25250397Sobrien error ("signature type `%s' declared `friend'", 25350397Sobrien IDENTIFIER_POINTER (TYPE_IDENTIFIER (friend_type))); 25450397Sobrien return; 25550397Sobrien } 25650397Sobrien if (processing_template_decl > template_class_depth (type)) 25750397Sobrien /* If the TYPE is a template then it makes sense for it to be 25850397Sobrien friends with itself; this means that each instantiation is 25950397Sobrien friends with all other instantiations. */ 26050397Sobrien is_template_friend = 1; 26150397Sobrien else if (comptypes (type, friend_type, 1)) 26250397Sobrien { 26350397Sobrien pedwarn ("class `%s' is implicitly friends with itself", 26450397Sobrien TYPE_NAME_STRING (type)); 26550397Sobrien return; 26650397Sobrien } 26750397Sobrien else 26850397Sobrien is_template_friend = 0; 26950397Sobrien 27050397Sobrien GNU_xref_hier (type, friend_type, 0, 0, 1); 27150397Sobrien 27250397Sobrien if (is_template_friend) 27350397Sobrien friend_type = CLASSTYPE_TI_TEMPLATE (friend_type); 27450397Sobrien 27550397Sobrien classes = CLASSTYPE_FRIEND_CLASSES (type); 27650397Sobrien while (classes 27750397Sobrien /* Stop if we find the same type on the list. */ 27850397Sobrien && !(TREE_CODE (TREE_VALUE (classes)) == TEMPLATE_DECL ? 27950397Sobrien friend_type == TREE_VALUE (classes) : 28050397Sobrien comptypes (TREE_VALUE (classes), friend_type, 1))) 28150397Sobrien classes = TREE_CHAIN (classes); 28250397Sobrien if (classes) 28350397Sobrien cp_warning ("`%T' is already a friend of `%T'", 28450397Sobrien TREE_VALUE (classes), type); 28550397Sobrien else 28650397Sobrien { 28750397Sobrien CLASSTYPE_FRIEND_CLASSES (type) 28850397Sobrien = tree_cons (NULL_TREE, friend_type, CLASSTYPE_FRIEND_CLASSES (type)); 28950397Sobrien } 29050397Sobrien} 29150397Sobrien 29250397Sobrien/* Main friend processor. This is large, and for modularity purposes, 29350397Sobrien has been removed from grokdeclarator. It returns `void_type_node' 29450397Sobrien to indicate that something happened, though a FIELD_DECL is 29550397Sobrien not returned. 29650397Sobrien 29750397Sobrien CTYPE is the class this friend belongs to. 29850397Sobrien 29950397Sobrien DECLARATOR is the name of the friend. 30050397Sobrien 30150397Sobrien DECL is the FUNCTION_DECL that the friend is. 30250397Sobrien 30350397Sobrien In case we are parsing a friend which is part of an inline 30450397Sobrien definition, we will need to store PARM_DECL chain that comes 30550397Sobrien with it into the DECL_ARGUMENTS slot of the FUNCTION_DECL. 30650397Sobrien 30750397Sobrien FLAGS is just used for `grokclassfn'. 30850397Sobrien 30950397Sobrien QUALS say what special qualifies should apply to the object 31050397Sobrien pointed to by `this'. */ 31150397Sobrien 31250397Sobrientree 31350397Sobriendo_friend (ctype, declarator, decl, parmdecls, flags, quals, funcdef_flag) 31450397Sobrien tree ctype, declarator, decl, parmdecls; 31550397Sobrien enum overload_flags flags; 31650397Sobrien tree quals; 31750397Sobrien int funcdef_flag; 31850397Sobrien{ 31950397Sobrien int is_friend_template = 0; 32050397Sobrien 32150397Sobrien /* Every decl that gets here is a friend of something. */ 32250397Sobrien DECL_FRIEND_P (decl) = 1; 32350397Sobrien 32450397Sobrien if (TREE_CODE (declarator) == TEMPLATE_ID_EXPR) 32550397Sobrien { 32650397Sobrien declarator = TREE_OPERAND (declarator, 0); 32750397Sobrien if (TREE_CODE (declarator) == LOOKUP_EXPR) 32850397Sobrien declarator = TREE_OPERAND (declarator, 0); 32950397Sobrien if (is_overloaded_fn (declarator)) 33050397Sobrien declarator = DECL_NAME (get_first_fn (declarator)); 33150397Sobrien } 33250397Sobrien 33350397Sobrien if (TREE_CODE (decl) == FUNCTION_DECL) 33450397Sobrien is_friend_template = processing_template_decl > 33550397Sobrien template_class_depth (current_class_type); 33650397Sobrien 33750397Sobrien if (ctype) 33850397Sobrien { 33950397Sobrien tree cname = TYPE_NAME (ctype); 34050397Sobrien if (TREE_CODE (cname) == TYPE_DECL) 34150397Sobrien cname = DECL_NAME (cname); 34250397Sobrien 34350397Sobrien /* A method friend. */ 34450397Sobrien if (TREE_CODE (decl) == FUNCTION_DECL) 34550397Sobrien { 34650397Sobrien if (flags == NO_SPECIAL && ctype && declarator == cname) 34750397Sobrien DECL_CONSTRUCTOR_P (decl) = 1; 34850397Sobrien 34950397Sobrien /* This will set up DECL_ARGUMENTS for us. */ 35050397Sobrien grokclassfn (ctype, cname, decl, flags, quals); 35150397Sobrien 35250397Sobrien if (is_friend_template) 35350397Sobrien decl = DECL_TI_TEMPLATE (push_template_decl (decl)); 35450397Sobrien 35550397Sobrien if (TYPE_SIZE (ctype) != 0 && template_class_depth (ctype) == 0) 35650397Sobrien decl = check_classfn (ctype, decl); 35750397Sobrien 35850397Sobrien /* TYPE_BEING_DEFINED is a hack for nested classes having 35950397Sobrien member functions of the enclosing class as friends. Will 36050397Sobrien go away as parsing of classes gets rewritten. */ 36150397Sobrien if (TREE_TYPE (decl) != error_mark_node) 36250397Sobrien { 36350397Sobrien if (TYPE_BEING_DEFINED (ctype) || 36450397Sobrien TYPE_SIZE (ctype) || template_class_depth (ctype) > 0) 36550397Sobrien add_friend (current_class_type, decl); 36650397Sobrien else 36750397Sobrien cp_error ("member `%D' declared as friend before type `%T' defined", 36850397Sobrien decl, ctype); 36950397Sobrien } 37050397Sobrien } 37150397Sobrien else 37250397Sobrien { 37350397Sobrien /* Possibly a bunch of method friends. */ 37450397Sobrien 37550397Sobrien /* Get the class they belong to. */ 37650397Sobrien tree ctype = IDENTIFIER_TYPE_VALUE (cname); 37750397Sobrien tree fields = lookup_fnfields (TYPE_BINFO (ctype), declarator, 0); 37850397Sobrien 37950397Sobrien if (fields) 38050397Sobrien add_friends (current_class_type, declarator, ctype); 38150397Sobrien else 38250397Sobrien cp_error ("method `%D' is not a member of class `%T'", 38350397Sobrien declarator, ctype); 38450397Sobrien decl = void_type_node; 38550397Sobrien } 38650397Sobrien } 38750397Sobrien else if (TREE_CODE (decl) == FUNCTION_DECL 38850397Sobrien && (MAIN_NAME_P (declarator) 38950397Sobrien || (IDENTIFIER_LENGTH (declarator) > 10 39050397Sobrien && IDENTIFIER_POINTER (declarator)[0] == '_' 39150397Sobrien && IDENTIFIER_POINTER (declarator)[1] == '_' 39250397Sobrien && strncmp (IDENTIFIER_POINTER (declarator)+2, 39350397Sobrien "builtin_", 8) == 0))) 39450397Sobrien { 39550397Sobrien /* raw "main", and builtin functions never gets overloaded, 39650397Sobrien but they can become friends. */ 39750397Sobrien add_friend (current_class_type, decl); 39850397Sobrien DECL_FRIEND_P (decl) = 1; 39950397Sobrien decl = void_type_node; 40050397Sobrien } 40150397Sobrien /* A global friend. 40250397Sobrien @@ or possibly a friend from a base class ?!? */ 40350397Sobrien else if (TREE_CODE (decl) == FUNCTION_DECL) 40450397Sobrien { 40550397Sobrien /* Friends must all go through the overload machinery, 40650397Sobrien even though they may not technically be overloaded. 40750397Sobrien 40850397Sobrien Note that because classes all wind up being top-level 40950397Sobrien in their scope, their friend wind up in top-level scope as well. */ 41050397Sobrien DECL_ASSEMBLER_NAME (decl) 41150397Sobrien = build_decl_overload (declarator, TYPE_ARG_TYPES (TREE_TYPE (decl)), 41250397Sobrien TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE); 41350397Sobrien DECL_ARGUMENTS (decl) = parmdecls; 41450397Sobrien if (funcdef_flag) 41550397Sobrien DECL_CLASS_CONTEXT (decl) = current_class_type; 41650397Sobrien 41750397Sobrien if (! DECL_USE_TEMPLATE (decl)) 41850397Sobrien { 41950397Sobrien /* We can call pushdecl here, because the TREE_CHAIN of this 42050397Sobrien FUNCTION_DECL is not needed for other purposes. Don't do this 42150397Sobrien for a template instantiation. */ 42250397Sobrien if (!is_friend_template) 42350397Sobrien { 42450397Sobrien /* However, we don't call pushdecl() for a friend 42550397Sobrien function of a template class, since in general, 42650397Sobrien such a declaration depends on template 42750397Sobrien parameters. Instead, we call pushdecl when the 42850397Sobrien class is instantiated. */ 42950397Sobrien if (template_class_depth (current_class_type) == 0) 43050397Sobrien decl = pushdecl (decl); 43150397Sobrien } 43250397Sobrien else 43350397Sobrien decl = push_template_decl (decl); 43450397Sobrien 43550397Sobrien if (! funcdef_flag && ! flag_guiding_decls && ! is_friend_template 43650397Sobrien && current_template_parms && uses_template_parms (decl)) 43750397Sobrien { 43850397Sobrien static int explained; 43950397Sobrien cp_warning ("friend declaration `%#D'", decl); 44050397Sobrien warning (" declares a non-template function"); 44150397Sobrien if (! explained) 44250397Sobrien { 44350397Sobrien warning (" (if this is not what you intended, make sure"); 44450397Sobrien warning (" the function template has already been declared,"); 44550397Sobrien warning (" and add <> after the function name here)"); 44650397Sobrien explained = 1; 44750397Sobrien } 44850397Sobrien } 44950397Sobrien } 45050397Sobrien 45150397Sobrien make_decl_rtl (decl, NULL_PTR, 1); 45250397Sobrien add_friend (current_class_type, 45350397Sobrien is_friend_template ? DECL_TI_TEMPLATE (decl) : decl); 45450397Sobrien DECL_FRIEND_P (decl) = 1; 45550397Sobrien } 45650397Sobrien else 45750397Sobrien { 45850397Sobrien /* @@ Should be able to ingest later definitions of this function 45950397Sobrien before use. */ 46050397Sobrien tree decl = lookup_name_nonclass (declarator); 46150397Sobrien if (decl == NULL_TREE) 46250397Sobrien { 46350397Sobrien cp_warning ("implicitly declaring `%T' as struct", declarator); 46450397Sobrien decl = xref_tag (record_type_node, declarator, NULL_TREE, 1); 46550397Sobrien decl = TYPE_MAIN_DECL (decl); 46650397Sobrien } 46750397Sobrien 46850397Sobrien /* Allow abbreviated declarations of overloaded functions, 46950397Sobrien but not if those functions are really class names. */ 47050397Sobrien if (TREE_CODE (decl) == TREE_LIST && TREE_TYPE (TREE_PURPOSE (decl))) 47150397Sobrien { 47250397Sobrien cp_warning ("`friend %T' archaic, use `friend class %T' instead", 47350397Sobrien declarator, declarator); 47450397Sobrien decl = TREE_TYPE (TREE_PURPOSE (decl)); 47550397Sobrien } 47650397Sobrien 47750397Sobrien if (TREE_CODE (decl) == TREE_LIST) 47850397Sobrien add_friends (current_class_type, TREE_PURPOSE (decl), NULL_TREE); 47950397Sobrien else 48050397Sobrien make_friend_class (current_class_type, TREE_TYPE (decl)); 48150397Sobrien decl = void_type_node; 48250397Sobrien } 48350397Sobrien return decl; 48450397Sobrien} 485