/* Help friends in C++.
- Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+ 2007, 2008, 2010 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)
+the Free Software Foundation; either version 3, 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 COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
+#include "coretypes.h"
+#include "tm.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. */
+/* 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)
tree friends = FRIEND_DECLS (list);
for (; friends ; friends = TREE_CHAIN (friends))
{
- if (TREE_VALUE (friends) == NULL_TREE)
- continue;
+ tree this_friend = TREE_VALUE (friends);
- if (supplicant == TREE_VALUE (friends))
- return 1;
+ if (this_friend == NULL_TREE)
+ continue;
- /* Temporarily, we are 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, this bit can
- go. */
- if (DECL_FUNCTION_MEMBER_P (supplicant)
- && same_type_p (TREE_TYPE (supplicant),
- TREE_TYPE (TREE_VALUE (friends))))
+ if (supplicant == this_friend)
return 1;
- if (TREE_CODE (TREE_VALUE (friends)) == TEMPLATE_DECL
- && is_specialization_of (supplicant,
- TREE_VALUE (friends)))
+ if (is_specialization_of_friend (supplicant, this_friend))
return 1;
}
break;
else
/* It's a type. */
{
- /* Nested classes are implicitly friends of their enclosing types, as
- per core issue 45 (this is a change from the standard). */
- for (context = supplicant;
- context && TYPE_P (context);
- context = TYPE_CONTEXT (context))
- if (type == context)
- return 1;
-
+ 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) :
+ 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_CONTEXT (supplicant);
- else if (! declp)
- /* Local classes have the same access as the enclosing function. */
- context = 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;
}
/* 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.
+
+ 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 (type, decl)
- tree type, decl;
+add_friend (tree type, tree decl, bool complain)
{
tree typedecl;
tree list;
tree name;
+ tree ctx;
if (decl == error_mark_node)
return;
{
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);
}
+ ctx = DECL_CONTEXT (decl);
+ if (ctx && CLASS_TYPE_P (ctx) && !uses_template_parms (ctx))
+ perform_or_defer_access_check (TYPE_BINFO (ctx), decl, decl);
+
+ maybe_add_class_template_decl_list (type, decl, /*friend_p=*/1);
+
DECL_FRIENDLIST (typedecl)
- = tree_cons (DECL_NAME (decl), build_tree_list (error_mark_node, decl),
+ = tree_cons (DECL_NAME (decl), build_tree_list (NULL_TREE, decl),
DECL_FRIENDLIST (typedecl));
if (!uses_template_parms (type))
- DECL_BEFRIENDING_CLASSES (decl)
+ DECL_BEFRIENDING_CLASSES (decl)
= tree_cons (NULL_TREE, type,
DECL_BEFRIENDING_CLASSES (decl));
}
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_AGGR_TYPE (friend_type))
- {
- cp_error ("invalid type `%T' declared `friend'", friend_type);
- return;
- }
+ /* 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
- if (CLASS_TYPE_P (friend_type)
- && CLASSTYPE_TEMPLATE_SPECIALIZATION (friend_type)
- && uses_template_parms (friend_type))
+ template <class T> struct A {
+ template <class U> struct B {
+ template <class V> template <class W>
+ friend class C<V>::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 (! MAYBE_CLASS_TYPE_P (friend_type))
{
- /* [temp.friend]
-
- Friend declarations shall not declare partial
- specializations. */
- cp_error ("partial specialization `%T' declared `friend'",
- friend_type);
+ /* N1791: If the type specifier in a friend declaration designates a
+ (possibly cv-qualified) class type, that class is declared as a
+ friend; otherwise, the friend declaration is ignored.
+
+ So don't complain in C++0x mode. */
+ if (cxx_dialect < cxx0x)
+ pedwarn (input_location, complain ? 0 : OPT_pedantic,
+ "invalid type %qT declared %<friend%>", friend_type);
return;
}
-
- if (processing_template_decl > template_class_depth (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. */
- is_template_friend = 1;
+ {
+ 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%>",
+ friend_type);
+ return;
+ }
+ }
else if (same_type_p (type, friend_type))
{
- cp_pedwarn ("class `%T' is implicitly friends with itself",
- type);
+ if (complain)
+ warning (0, "class %qT is implicitly friends with itself",
+ type);
return;
}
- else
- is_template_friend = 0;
- if (is_template_friend
- && (TREE_CODE (friend_type) == TYPENAME_TYPE
- || TREE_CODE (friend_type) == TEMPLATE_TYPE_PARM))
- {
- /* [temp.friend]
+ /* [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.
-
- But, we're looking at something like:
+ 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)
+ {
+ if (TREE_CODE (TYPENAME_TYPE_FULLNAME (friend_type))
+ == TEMPLATE_ID_EXPR)
+ {
+ /* template <class U> friend class T::X<U>; */
+ /* [temp.friend]
+ Friend declarations shall not declare partial
+ specializations. */
+ error ("partial specialization %qT declared %<friend%>",
+ friend_type);
+ return;
+ }
+ else
+ {
+ /* We will figure this out later. */
+ bool template_member_p = false;
- template <class T> friend typename S<T>::X;
+ tree ctype = TYPE_CONTEXT (friend_type);
+ tree name = TYPE_IDENTIFIER (friend_type);
+ tree decl;
- or:
+ if (!uses_template_parms_level (ctype, class_template_depth
+ + friend_depth))
+ template_member_p = true;
- template <class T> friend class T;
+ 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;
+ }
- which isn't any of these. */
- if (TREE_CODE (friend_type) == TYPENAME_TYPE)
- cp_error ("typename type `%T' declared `friend'",
- friend_type);
- else
- cp_error ("template parameter type `%T' declared `friend'",
- friend_type);
+ friend_type = CLASSTYPE_TI_TEMPLATE (TREE_TYPE (decl));
+ }
+ }
+ }
+ else if (TREE_CODE (friend_type) == TEMPLATE_TYPE_PARM)
+ {
+ /* template <class T> friend class T; */
+ error ("template parameter type %qT declared %<friend%>", friend_type);
return;
}
+ else if (!CLASSTYPE_TEMPLATE_INFO (friend_type))
+ {
+ /* template <class T> friend class A; where A is not a template */
+ error ("%q#T is not a template", friend_type);
+ return;
+ }
+ else
+ /* template <class T> 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) :
- 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
+ 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 (is_template_friend)
+ 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));
+ = 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, attrlist,
- flags, quals, funcdef_flag)
- tree ctype, declarator, decl, parmdecls, attrlist;
- 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;
- tree prefix_attributes, attributes;
+ gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
+ gcc_assert (!ctype || MAYBE_CLASS_TYPE_P (ctype));
/* Every decl that gets here is a friend of something. */
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. */
+
+ /* Set attributes here so if duplicate decl, will have proper attributes. */
+ cplus_decl_attributes (&decl, attrlist, 0);
+
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)
{
+ /* 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 <class T> struct A {
+ template <class U> struct B {
+ template <class V> template <class W>
+ friend void C<V>::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 (flags == NO_SPECIAL && ctype && declarator == cname)
+ if (flags == NO_SPECIAL && declarator == cname)
DECL_CONSTRUCTOR_P (decl) = 1;
- /* This will set up DECL_ARGUMENTS for us. */
- grokclassfn (ctype, decl, flags, quals);
+ grokclassfn (ctype, decl, flags);
- 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);
+ if (friend_depth)
+ {
+ if (!uses_template_parms_level (ctype, class_template_depth
+ + friend_depth))
+ template_member_p = true;
+ }
- /* 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 (processing_template_decl)
- 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 (COMPLETE_TYPE_P (ctype) || TYPE_BEING_DEFINED (ctype))
+ if (class_template_depth
+ || COMPLETE_TYPE_P (ctype)
+ || (CLASS_TYPE_P (ctype) && TYPE_BEING_DEFINED (ctype)))
{
- decl = check_classfn (ctype, decl);
+ 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);
+
+ if (template_member_p && decl && TREE_CODE (decl) == FUNCTION_DECL)
+ decl = DECL_TI_TEMPLATE (decl);
if (decl)
- add_friend (current_class_type, decl);
+ add_friend (current_class_type, decl, /*complain=*/true);
}
else
- cp_error ("member `%D' declared as friend before type `%T' defined",
+ 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. */
- DECL_ARGUMENTS (decl) = parmdecls;
if (funcdef_flag)
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 (warn_nontemplate_friend
- && ! funcdef_flag && ! 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. 11.5p11:
+
+ If a friend declaration appears in a local class (9.8) and
+ the name specified is an unqualified name, a prior
+ declaration is looked up without considering scopes that
+ are outside the innermost enclosing non-class scope. For a
+ friend function declaration, if there is no prior
+ declaration, the program is ill-formed. */
+ tree t = lookup_name_innermost_nonclass_level (DECL_NAME (decl));
+ if (t)
+ decl = pushdecl_maybe_friend (decl, /*is_friend=*/true);
+ else
+ {
+ error ("friend declaration %qD in local class without "
+ "prior declaration", decl);
+ return error_mark_node;
+ }
+ }
+ 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' declares a non-template function", decl);
- if (! explained)
+ bool warned;
+
+ warned = warning (OPT_Wnon_template_friend, "friend declaration "
+ "%q#D declares a non-template function", decl);
+ if (! explained && warned)
{
- 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.");
+ inform (input_location, "(if this is not what you intended, make sure "
+ "the function template has already been declared "
+ "and add <> after the function name here) ");
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 (decl == error_mark_node)
+ return error_mark_node;
- if (attrlist)
- {
- attributes = TREE_PURPOSE (attrlist);
- prefix_attributes = TREE_VALUE (attrlist);
+ add_friend (current_class_type,
+ is_friend_template ? DECL_TI_TEMPLATE (decl) : decl,
+ /*complain=*/true);
+ DECL_FRIEND_P (decl) = 1;
}
- 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;
}