OSDN Git Service

2002-08-24 Matt Austern <austern@apple.com>
[pf3gnuchains/gcc-fork.git] / gcc / cp / friend.c
index 8bcdcc4..441be67 100644 (file)
@@ -1,5 +1,5 @@
 /* Help friends in C++.
-   Copyright (C) 1997, 1998, 1999 Free Software Foundation, Inc.
+   Copyright (C) 1997, 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -22,14 +22,12 @@ Boston, MA 02111-1307, USA.  */
 #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"
 
-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 non-zero if SUPPLICANT is a friend of TYPE.  */
@@ -45,49 +43,33 @@ is_friend (type, supplicant)
   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 (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))
+                 /* 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))))
                    return 1;
@@ -104,8 +86,13 @@ is_friend (type, supplicant)
   else
     /* It's a type.  */
     {
-      if (type == supplicant)
-       return 1;
+      /* 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;
       
       list = CLASSTYPE_FRIEND_CLASSES (TREE_TYPE (TYPE_MAIN_DECL (type)));
       for (; list ; list = TREE_CHAIN (list))
@@ -120,10 +107,10 @@ is_friend (type, supplicant)
     }      
 
   if (declp && DECL_FUNCTION_MEMBER_P (supplicant))
-    context = DECL_CLASS_CONTEXT (supplicant);
+    context = DECL_CONTEXT (supplicant);
   else if (! declp)
     /* Local classes have the same access as the enclosing function.  */
-    context = hack_decl_function_context (TYPE_MAIN_DECL (supplicant));
+    context = decl_function_context (TYPE_MAIN_DECL (supplicant));
   else
     context = NULL_TREE;
 
@@ -140,24 +127,32 @@ 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.  */
 
-static void
+void
 add_friend (type, decl)
      tree type, decl;
 {
-  tree typedecl = TYPE_MAIN_DECL (type);
-  tree list = DECL_FRIENDLIST (typedecl);
-  tree name = DECL_NAME (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 == 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'",
+                 warning ("`%D' is already a friend of class `%T'",
                              decl, type);
                  cp_warning_at ("previous friend declaration of `%D'",
                                 TREE_VALUE (friends));
@@ -170,69 +165,14 @@ add_friend (type, decl)
        }
       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.  */
-
-static 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 == 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 (error_mark_node, 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
@@ -252,29 +192,25 @@ make_friend_class (type, friend_type)
   tree classes;
   int is_template_friend;
 
-  if (IS_SIGNATURE (type))
+  if (! IS_AGGR_TYPE (friend_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);
+      error ("invalid type `%T' declared `friend'", friend_type);
       return;
     }
 
-  if (CLASSTYPE_TEMPLATE_SPECIALIZATION (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.  */
-      cp_error ("partial specialization `%T' declared `friend'",
+      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
@@ -282,14 +218,39 @@ make_friend_class (type, friend_type)
     is_template_friend = 1;
   else if (same_type_p (type, friend_type))
     {
-      pedwarn ("class `%s' is implicitly friends with itself",
-              TYPE_NAME_STRING (type));
+      pedwarn ("class `%T' is implicitly friends with itself",
+                 type);
       return;
     }
   else
     is_template_friend = 0;
 
-  GNU_xref_hier (type, friend_type, 0, 0, 1);
+  /* [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 (!is_template_friend)
+    ;/* ok */
+  else if (TREE_CODE (friend_type) == TYPENAME_TYPE)
+    {
+      /* template <class T> friend typename S<T>::X; */
+      error ("typename type `%#T' declared `friend'", friend_type);
+      return;
+    }
+  else if (TREE_CODE (friend_type) == TEMPLATE_TYPE_PARM)
+    {
+      /* template <class T> friend class T; */
+      error ("template parameter type `%T' 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 ("`%#T' is not a template", friend_type);
+      return;
+    }
 
   if (is_template_friend)
     friend_type = CLASSTYPE_TI_TEMPLATE (friend_type);
@@ -302,12 +263,18 @@ make_friend_class (type, friend_type)
              same_type_p (TREE_VALUE (classes), friend_type)))
     classes = TREE_CHAIN (classes);
   if (classes) 
-    cp_warning ("`%T' is already a friend of `%T'",
+    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)); 
     }
 }
 
@@ -332,8 +299,9 @@ make_friend_class (type, friend_type)
    pointed to by `this'.  */
 
 tree
-do_friend (ctype, declarator, decl, parmdecls, flags, quals, funcdef_flag)
-     tree ctype, declarator, decl, parmdecls;
+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;
@@ -352,8 +320,10 @@ do_friend (ctype, declarator, decl, parmdecls, flags, quals, funcdef_flag)
        declarator = DECL_NAME (get_first_fn (declarator));
     }
 
-  if (TREE_CODE (decl) == FUNCTION_DECL)
-    is_friend_template = PROCESSING_REAL_TEMPLATE_DECL_P ();
+  if (TREE_CODE (decl) != FUNCTION_DECL)
+    abort ();
+
+  is_friend_template = PROCESSING_REAL_TEMPLATE_DECL_P ();
 
   if (ctype)
     {
@@ -362,53 +332,35 @@ do_friend (ctype, declarator, decl, parmdecls, flags, quals, funcdef_flag)
        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, 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 (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 (flags == NO_SPECIAL && ctype && declarator == cname)
-           DECL_CONSTRUCTOR_P (decl) = 1;
-
-         /* This will set up DECL_ARGUMENTS for us.  */
-         grokclassfn (ctype, decl, flags, quals);
+         decl = check_classfn (ctype, decl);
 
-         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))
+         if (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 (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);
        }
       else
-       {
-         /* Possibly a bunch of method friends.  */
-
-         /* Get the class they belong to.  */
-         tree ctype = IDENTIFIER_TYPE_VALUE (cname);
-         tree fields = lookup_fnfields (TYPE_BINFO (ctype), declarator, 0);
-
-         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;
-       }
+       error ("member `%D' declared as friend before type `%T' defined",
+                 decl, ctype);
     }
   /* A global friend.
      @@ or possibly a friend from a base class ?!?  */
@@ -421,72 +373,67 @@ do_friend (ctype, declarator, decl, parmdecls, flags, quals, funcdef_flag)
         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;
+       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 
+         /* 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=*/1); 
+         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 (decl);
+         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);
+             pop_nested_namespace (ns);
+           }
 
-         if (warn_nontemplate_friend
-             && ! funcdef_flag && ! flag_guiding_decls && ! is_friend_template
-             && current_template_parms && uses_template_parms (decl))
+         if (warn)
            {
              static int explained;
-             cp_warning ("friend declaration `%#D'", decl);
-             warning ("  declares a non-template function");
+             warning ("friend declaration `%#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 ("  -Wno-non-template-friend disables this warning.");
+                 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;
                }
            }
        }
 
-      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;
     }
-  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;
 }