X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fcp%2Ffriend.c;h=d92df5f6eba3df85ad1519eba905cbcd3a777c61;hb=2f7a9ec1f5fb23e958da404c28d177e6905482e6;hp=561c9d747b321beaaf2f1d86a6847d77c80dea9a;hpb=f47cdd21182b35b9f35d2e2400597b4432515dc6;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/cp/friend.c b/gcc/cp/friend.c index 561c9d747b3..d92df5f6eba 100644 --- a/gcc/cp/friend.c +++ b/gcc/cp/friend.c @@ -1,98 +1,74 @@ /* Help friends in C++. - Copyright (C) 1997 Free Software Foundation, Inc. + Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 + Free Software Foundation, Inc. -This file is part of GNU CC. +This file is part of GCC. -GNU CC is free software; you can redistribute it and/or modify +GCC 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, +GCC 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. */ +along with GCC; see the file COPYING. If not, write to +the Free Software Foundation, 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ #include "config.h" #include "system.h" +#include "coretypes.h" +#include "tm.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 nonzero if SUPPLICANT is a friend of TYPE. */ + int -is_friend (type, supplicant) - tree type, supplicant; +is_friend (tree type, tree supplicant) { int declp; - register tree list; + tree list; tree context; 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 (comptypes (ctype, TREE_PURPOSE (friends), 1)) - return 1; + tree friend = TREE_VALUE (friends); - if (TREE_VALUE (friends) == NULL_TREE) + if (friend == 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)) - && comptypes (TREE_TYPE (supplicant), - TREE_TYPE (TREE_VALUE (friends)), 1)) + if (supplicant == friend) return 1; - if (TREE_CODE (TREE_VALUE (friends)) == TEMPLATE_DECL - && is_specialization_of (supplicant, - TREE_VALUE (friends))) + if (is_specialization_of_friend (supplicant, friend)) return 1; } break; @@ -102,30 +78,40 @@ is_friend (type, supplicant) else /* It's a type. */ { - if (type == supplicant) + if (same_type_p (supplicant, type)) 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) : - comptypes (supplicant, t, 1)) + if (TREE_CODE (t) == TEMPLATE_DECL ? + is_specialization_of_friend (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)); + if (declp) + { + if (DECL_FUNCTION_MEMBER_P (supplicant)) + context = DECL_CONTEXT (supplicant); + else + context = NULL_TREE; + } else - context = NULL_TREE; + { + if (TYPE_CLASS_SCOPE_P (supplicant)) + /* Nested classes get the same access as their enclosing types, as + per DR 45 (this is a change from the standard). */ + context = TYPE_CONTEXT (supplicant); + else + /* Local classes have the same access as the enclosing function. */ + context = decl_function_context (TYPE_MAIN_DECL (supplicant)); + } - /* A namespace is not friend to anybody. */ + /* A namespace is not friend to anybody. */ if (context && TREE_CODE (context) == NAMESPACE_DECL) context = NULL_TREE; @@ -136,101 +122,66 @@ is_friend (type, supplicant) } /* Add a new friend to the friends of the aggregate type TYPE. - DECL is the FUNCTION_DECL of the friend being added. */ + DECL is the FUNCTION_DECL of the friend being added. -static void -add_friend (type, decl) - tree type, decl; + If COMPLAIN is true, warning about duplicate friend is issued. + We want to have this diagnostics during parsing but not + when a template is being instantiated. */ + +void +add_friend (tree type, tree decl, bool complain) { - tree typedecl = TYPE_MAIN_DECL (type); - tree list = DECL_FRIENDLIST (typedecl); - tree name = DECL_NAME (decl); + tree typedecl; + tree list; + tree name; + tree ctx; + + 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'", - decl, type); - cp_warning_at ("previous friend declaration of `%D'", - TREE_VALUE (friends)); + if (complain) + warning (0, "%qD is already a friend of class %qT", + decl, type); return; } } - TREE_VALUE (list) = tree_cons (error_mark_node, decl, + + maybe_add_class_template_decl_list (type, decl, /*friend_p=*/1); + + TREE_VALUE (list) = tree_cons (NULL_TREE, 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 (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. */ + ctx = DECL_CONTEXT (decl); + if (ctx && CLASS_TYPE_P (ctx) && !uses_template_parms (ctx)) + perform_or_defer_access_check (TYPE_BINFO (ctx), decl); -static void -add_friends (type, name, friend_type) - tree type, name, friend_type; -{ - tree typedecl = TYPE_MAIN_DECL (type); - tree list = DECL_FRIENDLIST (typedecl); + maybe_add_class_template_decl_list (type, decl, /*friend_p=*/1); - 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 (NULL_TREE, 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 @@ -241,103 +192,224 @@ add_friends (type, name, friend_type) 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! */ + be in use at the same time! + + If COMPLAIN is true, warning about duplicate friend is issued. + We want to have this diagnostics during parsing but not + when a template is being instantiated. */ void -make_friend_class (type, friend_type) - tree type, friend_type; +make_friend_class (tree type, tree friend_type, bool complain) { tree classes; - int is_template_friend; - if (IS_SIGNATURE (type)) + /* CLASS_TEMPLATE_DEPTH counts the number of template headers for + the enclosing class. FRIEND_DEPTH counts the number of template + headers used for this friend declaration. TEMPLATE_MEMBER_P, + defined inside the `if' block for TYPENAME_TYPE case, is true if + a template header in FRIEND_DEPTH is intended for DECLARATOR. + For example, the code + + template struct A { + template struct B { + template template + friend class C::D; + }; + }; + + will eventually give the following results + + 1. CLASS_TEMPLATE_DEPTH equals 2 (for `T' and `U'). + 2. FRIEND_DEPTH equals 2 (for `V' and `W'). + 3. TEMPLATE_MEMBER_P is true (for `W'). + + The friend is a template friend iff FRIEND_DEPTH is nonzero. */ + + int class_template_depth = template_class_depth (type); + int friend_depth = processing_template_decl - class_template_depth; + + if (! IS_AGGR_TYPE (friend_type)) { - error ("`friend' declaration in signature definition"); + error ("invalid type %qT declared %", friend_type); return; } - if (IS_SIGNATURE (friend_type)) + + if (friend_depth) + /* 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. */ { - error ("signature type `%s' declared `friend'", - IDENTIFIER_POINTER (TYPE_IDENTIFIER (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. */ + error ("partial specialization %qT declared %", + friend_type); + return; + } + } + else if (same_type_p (type, friend_type)) + { + if (complain) + pedwarn ("class %qT is implicitly friends with itself", + type); return; } - if (CLASSTYPE_TEMPLATE_SPECIALIZATION (friend_type) - && uses_template_parms (friend_type)) + /* [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 (!friend_depth) + ;/* ok */ + else if (TREE_CODE (friend_type) == TYPENAME_TYPE) { - /* [temp.friend] - - Friend declarations shall not declare partial - specializations. */ - cp_error ("partial specialization `%T' declared `friend'", - friend_type); + if (TREE_CODE (TYPENAME_TYPE_FULLNAME (friend_type)) + == TEMPLATE_ID_EXPR) + { + /* template friend class T::X; */ + /* [temp.friend] + Friend declarations shall not declare partial + specializations. */ + error ("partial specialization %qT declared %", + friend_type); + return; + } + else + { + /* We will figure this out later. */ + bool template_member_p = false; + + tree ctype = TYPE_CONTEXT (friend_type); + tree name = TYPE_IDENTIFIER (friend_type); + tree decl; + + if (!uses_template_parms_level (ctype, class_template_depth + + friend_depth)) + template_member_p = true; + + if (class_template_depth) + { + /* We rely on tsubst_friend_class to check the + validity of the declaration later. */ + if (template_member_p) + friend_type + = make_unbound_class_template (ctype, + name, + current_template_parms, + tf_error); + else + friend_type + = make_typename_type (ctype, name, class_type, tf_error); + } + else + { + decl = lookup_member (ctype, name, 0, true); + if (!decl) + { + error ("%qT is not a member of %qT", name, ctype); + return; + } + if (template_member_p && !DECL_CLASS_TEMPLATE_P (decl)) + { + error ("%qT is not a member class template of %qT", + name, ctype); + error ("%q+D declared here", decl); + return; + } + if (!template_member_p && (TREE_CODE (decl) != TYPE_DECL + || !CLASS_TYPE_P (TREE_TYPE (decl)))) + { + error ("%qT is not a nested class of %qT", + name, ctype); + error ("%q+D declared here", decl); + return; + } + + friend_type = CLASSTYPE_TI_TEMPLATE (TREE_TYPE (decl)); + } + } + } + else if (TREE_CODE (friend_type) == TEMPLATE_TYPE_PARM) + { + /* template friend class T; */ + error ("template parameter type %qT declared %", 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 (comptypes (type, friend_type, 1)) + else if (!CLASSTYPE_TEMPLATE_INFO (friend_type)) { - pedwarn ("class `%s' is implicitly friends with itself", - TYPE_NAME_STRING (type)); + /* template friend class A; where A is not a template */ + error ("%q#T is not a template", friend_type); return; } else - is_template_friend = 0; + /* template friend class A; where A is a template */ + friend_type = CLASSTYPE_TI_TEMPLATE (friend_type); - GNU_xref_hier (type, friend_type, 0, 0, 1); + if (friend_type == error_mark_node) + return; - if (is_template_friend) - friend_type = CLASSTYPE_TI_TEMPLATE (friend_type); + /* See if it is already a friend. */ + for (classes = CLASSTYPE_FRIEND_CLASSES (type); + classes; + classes = TREE_CHAIN (classes)) + { + tree probe = TREE_VALUE (classes); - 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) : - comptypes (TREE_VALUE (classes), friend_type, 1))) - classes = TREE_CHAIN (classes); - if (classes) - cp_warning ("`%T' is already a friend of `%T'", - TREE_VALUE (classes), type); - else + if (TREE_CODE (friend_type) == TEMPLATE_DECL) + { + if (friend_type == probe) + { + if (complain) + warning (0, "%qD is already a friend of %qT", probe, type); + break; + } + } + else if (TREE_CODE (probe) != TEMPLATE_DECL) + { + if (same_type_p (probe, friend_type)) + { + if (complain) + warning (0, "%qT is already a friend of %qT", probe, type); + break; + } + } + } + + if (!classes) { + maybe_add_class_template_decl_list (type, friend_type, /*friend_p=*/1); + CLASSTYPE_FRIEND_CLASSES (type) = tree_cons (NULL_TREE, friend_type, CLASSTYPE_FRIEND_CLASSES (type)); + if (TREE_CODE (friend_type) == TEMPLATE_DECL) + 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'. */ +/* Record DECL (a FUNCTION_DECL) as a friend of the + CURRENT_CLASS_TYPE. If DECL is a member function, CTYPE is the + class of which it is a member, as named in the friend declaration. + DECLARATOR is the name of the friend. FUNCDEF_FLAG is true if the + friend declaration is a definition of the function. FLAGS is as + for grokclass fn. */ tree -do_friend (ctype, declarator, decl, parmdecls, flags, quals, funcdef_flag) - tree ctype, declarator, decl, parmdecls; - enum overload_flags flags; - tree quals; - int funcdef_flag; +do_friend (tree ctype, tree declarator, tree decl, + tree attrlist, enum overload_flags flags, + bool funcdef_flag) { - int is_friend_template = 0; + gcc_assert (TREE_CODE (decl) == FUNCTION_DECL); + gcc_assert (!ctype || IS_AGGR_TYPE (ctype)); /* Every decl that gets here is a friend of something. */ DECL_FRIEND_P (decl) = 1; @@ -345,155 +417,165 @@ do_friend (ctype, declarator, decl, parmdecls, flags, quals, funcdef_flag) 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) - is_friend_template = PROCESSING_REAL_TEMPLATE_DECL_P (); - if (ctype) { + /* CLASS_TEMPLATE_DEPTH counts the number of template headers for + the enclosing class. FRIEND_DEPTH counts the number of template + headers used for this friend declaration. TEMPLATE_MEMBER_P is + true if a template header in FRIEND_DEPTH is intended for + DECLARATOR. For example, the code + + template struct A { + template struct B { + template template + friend void C::f(W); + }; + }; + + will eventually give the following results + + 1. CLASS_TEMPLATE_DEPTH equals 2 (for `T' and `U'). + 2. FRIEND_DEPTH equals 2 (for `V' and `W'). + 3. TEMPLATE_MEMBER_P is true (for `W'). */ + + int class_template_depth = template_class_depth (current_class_type); + int friend_depth = processing_template_decl - class_template_depth; + /* We will figure this out later. */ + bool template_member_p = false; + tree cname = TYPE_NAME (ctype); if (TREE_CODE (cname) == TYPE_DECL) 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, cname, decl, flags, quals); - - if (is_friend_template) - decl = DECL_TI_TEMPLATE (push_template_decl (decl)); + if (flags == NO_SPECIAL && declarator == cname) + DECL_CONSTRUCTOR_P (decl) = 1; - if (TYPE_SIZE (ctype) != 0 && template_class_depth (ctype) == 0) - decl = check_classfn (ctype, decl); + grokclassfn (ctype, decl, flags); - /* TYPE_BEING_DEFINED is a hack for nested classes having - member functions of the enclosing class as friends. Will - go away as parsing of classes gets rewritten. */ - if (TREE_TYPE (decl) != error_mark_node) - { - if (TYPE_BEING_DEFINED (ctype) || - TYPE_SIZE (ctype) || template_class_depth (ctype) > 0) - add_friend (current_class_type, decl); - else - cp_error ("member `%D' declared as friend before type `%T' defined", - decl, ctype); - } + if (friend_depth) + { + if (!uses_template_parms_level (ctype, class_template_depth + + friend_depth)) + template_member_p = true; } - else + + /* 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. */ + if (class_template_depth + || COMPLETE_TYPE_P (ctype) + || TYPE_BEING_DEFINED (ctype)) { - /* Possibly a bunch of method friends. */ + if (DECL_TEMPLATE_INFO (decl)) + /* DECL is a template specialization. No need to + build a new TEMPLATE_DECL. */ + ; + else if (class_template_depth) + /* We rely on tsubst_friend_function to check the + validity of the declaration later. */ + decl = push_template_decl_real (decl, /*is_friend=*/true); + else + decl = check_classfn (ctype, decl, + template_member_p + ? current_template_parms + : NULL_TREE); - /* Get the class they belong to. */ - tree ctype = IDENTIFIER_TYPE_VALUE (cname); - tree fields = lookup_fnfields (TYPE_BINFO (ctype), declarator, 0); + if (template_member_p && decl && TREE_CODE (decl) == FUNCTION_DECL) + decl = DECL_TI_TEMPLATE (decl); - 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; + if (decl) + add_friend (current_class_type, decl, /*complain=*/true); } - } - else if (TREE_CODE (decl) == FUNCTION_DECL - && (MAIN_NAME_P (declarator) - || (IDENTIFIER_LENGTH (declarator) > 10 - && IDENTIFIER_POINTER (declarator)[0] == '_' - && IDENTIFIER_POINTER (declarator)[1] == '_' - && strncmp (IDENTIFIER_POINTER (declarator)+2, - "builtin_", 8) == 0))) - { - /* raw "main", and builtin functions never gets overloaded, - but they can become friends. */ - add_friend (current_class_type, decl); - DECL_FRIEND_P (decl) = 1; - decl = void_type_node; + else + error ("member %qD declared as friend before type %qT defined", + decl, ctype); } /* A global friend. @@ or possibly a friend from a base class ?!? */ else if (TREE_CODE (decl) == FUNCTION_DECL) { + int is_friend_template = PROCESSING_REAL_TEMPLATE_DECL_P (); + /* 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. */ - set_mangled_name_for_decl (decl); - 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 - decl = push_template_decl_real (decl, /*is_friend=*/1); - - if (! funcdef_flag && ! flag_guiding_decls && ! is_friend_template - && current_template_parms && uses_template_parms (decl)) + /* 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=*/true); + 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_maybe_friend (decl, /*is_friend=*/true); + 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, /*is_friend=*/true); + pop_nested_namespace (ns); + } + + if (warn) { static int explained; - cp_warning ("friend declaration `%#D'", decl); - warning (" declares a non-template function"); + warning (0, "friend declaration %q#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 (0, "(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); + if (decl == error_mark_node) + return error_mark_node; + + add_friend (current_class_type, + is_friend_template ? DECL_TI_TEMPLATE (decl) : decl, + /*complain=*/true); 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; }