OSDN Git Service

2007-07-14 Rafael Avila de Espindola <espindola@google.com>
[pf3gnuchains/gcc-fork.git] / gcc / cp / friend.c
index 95f98c4..96c6dc6 100644 (file)
@@ -1,6 +1,6 @@
 /* Help friends in C++.
    Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
-   2007  Free Software Foundation, Inc.
+   2007, 2008  Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -227,7 +227,7 @@ make_friend_class (tree type, tree friend_type, bool complain)
   int class_template_depth = template_class_depth (type);
   int friend_depth = processing_template_decl - class_template_depth;
 
-  if (! IS_AGGR_TYPE (friend_type))
+  if (! MAYBE_CLASS_TYPE_P (friend_type))
     {
       error ("invalid type %qT declared %<friend%>", friend_type);
       return;
@@ -253,7 +253,7 @@ make_friend_class (tree type, tree friend_type, bool complain)
   else if (same_type_p (type, friend_type))
     {
       if (complain)
-       pedwarn ("class %qT is implicitly friends with itself",
+       warning (0, "class %qT is implicitly friends with itself",
                 type);
       return;
     }
@@ -408,11 +408,18 @@ do_friend (tree ctype, tree declarator, tree decl,
           bool funcdef_flag)
 {
   gcc_assert (TREE_CODE (decl) == FUNCTION_DECL);
-  gcc_assert (!ctype || IS_AGGR_TYPE (ctype));
+  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);
@@ -468,7 +475,7 @@ do_friend (tree ctype, tree declarator, tree decl,
         the process of being defined.  */
       if (class_template_depth
          || COMPLETE_TYPE_P (ctype)
-         || TYPE_BEING_DEFINED (ctype))
+         || (CLASS_TYPE_P (ctype) && TYPE_BEING_DEFINED (ctype)))
        {
          if (DECL_TEMPLATE_INFO (decl))
            /* DECL is a template specialization.  No need to
@@ -526,11 +533,25 @@ do_friend (tree ctype, tree declarator, tree decl,
               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);
+           {
+             /* 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
@@ -568,12 +589,5 @@ do_friend (tree ctype, tree declarator, tree 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.  */
-
-  /* Set attributes here so if duplicate decl, will have proper attributes.  */
-  cplus_decl_attributes (&decl, attrlist, 0);
-
   return decl;
 }