OSDN Git Service

2005-07-02 Zack Weinberg <zack@codesourcery.com>
[pf3gnuchains/gcc-fork.git] / gcc / cp / friend.c
index c81bd93..4e1a209 100644 (file)
@@ -1,5 +1,5 @@
 /* Help friends in C++.
-   Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004
+   Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
    Free Software Foundation, Inc.
 
 This file is part of GCC.
@@ -16,8 +16,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GCC; see the file COPYING.  If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA.  */
+the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA.  */
 
 #include "config.h"
 #include "system.h"
@@ -85,18 +85,18 @@ is_friend (tree type, tree supplicant)
           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))
        {
          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);
@@ -129,6 +129,7 @@ add_friend (tree type, tree decl, bool complain)
   tree typedecl;
   tree list;
   tree name;
+  tree ctx;
 
   if (decl == error_mark_node)
     return;
@@ -148,7 +149,7 @@ add_friend (tree type, tree decl, bool complain)
              if (decl == TREE_VALUE (friends))
                {
                  if (complain)
-                   warning ("`%D' is already a friend of class `%T'",
+                   warning (0, "%qD is already a friend of class %qT",
                             decl, type);
                  return;
                }
@@ -163,8 +164,9 @@ add_friend (tree type, tree decl, bool complain)
       list = TREE_CHAIN (list);
     }
 
-  if (DECL_CLASS_SCOPE_P (decl))
-    perform_or_defer_access_check (TYPE_BINFO (DECL_CONTEXT (decl)), decl);
+  ctx = DECL_CONTEXT (decl);
+  if (ctx && CLASS_TYPE_P (ctx) && !uses_template_parms (ctx))
+    perform_or_defer_access_check (TYPE_BINFO (ctx), decl);
 
   maybe_add_class_template_decl_list (type, decl, /*friend_p=*/1);
 
@@ -172,7 +174,7 @@ add_friend (tree type, tree decl, bool complain)
     = 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));
 }
@@ -195,15 +197,39 @@ void
 make_friend_class (tree type, tree friend_type, bool complain)
 {
   tree classes;
-  int is_template_friend;
+
+  /* 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 <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 (! IS_AGGR_TYPE (friend_type))
     {
-      error ("invalid type `%T' declared `friend'", friend_type);
+      error ("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.  */
@@ -215,22 +241,18 @@ make_friend_class (tree type, tree friend_type, bool complain)
          /* [temp.friend]
             Friend declarations shall not declare partial
             specializations.  */
-         error ("partial specialization `%T' declared `friend'",
+         error ("partial specialization %qT declared %<friend%>",
                 friend_type);
          return;
        }
-  
-      is_template_friend = 1;
     }
   else if (same_type_p (type, friend_type))
     {
       if (complain)
-       pedwarn ("class `%T' is implicitly friends with itself",
+       pedwarn ("class %qT is implicitly friends with itself",
                 type);
       return;
     }
-  else
-    is_template_friend = 0;
 
   /* [temp.friend]
 
@@ -238,30 +260,95 @@ make_friend_class (tree type, tree friend_type, bool complain)
      class template, a specialization of a function template or
      class template, or an ordinary (nontemplate) function or
      class.  */
-  if (!is_template_friend)
+  if (!friend_depth)
     ;/* 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;
+      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;
+
+         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 <class T> friend class T; */
-      error ("template parameter type `%T' declared `friend'", friend_type);
+      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 ("`%#T' is not a template", friend_type);
+      error ("%q#T is not a template", friend_type);
       return;
     }
-
-  if (is_template_friend)
+  else
+    /* template <class T> friend class A; where A is a template */
     friend_type = CLASSTYPE_TI_TEMPLATE (friend_type);
 
+  if (friend_type == error_mark_node)
+    return;
+
   /* See if it is already a friend.  */
   for (classes = CLASSTYPE_FRIEND_CLASSES (type);
        classes;
@@ -274,8 +361,7 @@ make_friend_class (tree type, tree friend_type, bool complain)
          if (friend_type == probe)
            {
              if (complain)
-               warning ("`%D' is already a friend of `%T'",
-                        probe, type);
+               warning (0, "%qD is already a friend of %qT", probe, type);
              break;
            }
        }
@@ -284,29 +370,28 @@ make_friend_class (tree type, tree friend_type, bool complain)
          if (same_type_p (probe, friend_type))
            {
              if (complain)
-               warning ("`%T' is already a friend of `%T'",
-                        probe, type);
+               warning (0, "%qT is already a friend of %qT", probe, type);
              break;
            }
        }
     }
-  
-  if (!classes) 
+
+  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. 
+/* Main friend processor.
 
    CTYPE is the class this friend belongs to.
 
@@ -321,7 +406,8 @@ make_friend_class (tree type, tree friend_type, bool complain)
 
 tree
 do_friend (tree ctype, tree declarator, tree decl,
-          tree attrlist, enum overload_flags flags, tree quals,
+          tree attrlist, enum overload_flags flags,
+          cp_cv_quals quals,
           int funcdef_flag)
 {
   /* Every decl that gets here is a friend of something.  */
@@ -334,8 +420,7 @@ do_friend (tree ctype, tree declarator, tree decl,
        declarator = DECL_NAME (get_first_fn (declarator));
     }
 
-  if (TREE_CODE (decl) != FUNCTION_DECL)
-    abort ();
+  gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
 
   if (ctype)
     {
@@ -397,7 +482,10 @@ do_friend (tree ctype, tree declarator, tree decl,
               validity of the declaration later.  */
            decl = push_template_decl_real (decl, /*is_friend=*/1);
          else
-           decl = check_classfn (ctype, decl, template_member_p);
+           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);
@@ -406,7 +494,7 @@ do_friend (tree ctype, tree declarator, tree decl,
            add_friend (current_class_type, decl, /*complain=*/true);
        }
       else
-       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.
@@ -439,7 +527,7 @@ do_friend (tree ctype, tree declarator, tree decl,
               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); 
+           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
@@ -449,11 +537,11 @@ do_friend (tree ctype, tree declarator, tree 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.  */
+                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);
@@ -462,10 +550,14 @@ do_friend (tree ctype, tree declarator, tree decl,
          if (warn)
            {
              static int explained;
-             warning ("friend declaration `%#D' declares a non-template function", decl);
+             warning (0, "friend declaration %q#D declares a non-template "
+                      "function", decl);
              if (! explained)
                {
-                 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");
+                 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;
                }
            }
@@ -473,8 +565,8 @@ do_friend (tree ctype, tree declarator, tree decl,
 
       if (decl == error_mark_node)
        return error_mark_node;
-      
-      add_friend (current_class_type, 
+
+      add_friend (current_class_type,
                  is_friend_template ? DECL_TI_TEMPLATE (decl) : decl,
                  /*complain=*/true);
       DECL_FRIEND_P (decl) = 1;