PR c++/34912
authorjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 22 Jan 2008 19:50:37 +0000 (19:50 +0000)
committerjason <jason@138bc75d-0d04-0410-961f-82ee72b054a4>
Tue, 22 Jan 2008 19:50:37 +0000 (19:50 +0000)
        * friend.c (do_friend): Check for prior declaration of a friend
        function of a local class.
        * name-lookup.c (lookup_name_innermost_nonclass_level):
        No longer static.
        * name-lookup.h: Declare it.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@131740 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/cp/ChangeLog
gcc/cp/friend.c
gcc/cp/name-lookup.c
gcc/cp/name-lookup.h
gcc/testsuite/g++.dg/lookup/friend12.C [new file with mode: 0644]
gcc/testsuite/g++.dg/parse/local-class1.C
gcc/testsuite/g++.old-deja/g++.jason/scoping12.C

index 235f7cb..45297de 100644 (file)
@@ -1,3 +1,12 @@
+2008-01-22  Jason Merrill  <jason@redhat.com>
+
+       PR c++/34912
+       * friend.c (do_friend): Check for prior declaration of a friend 
+       function of a local class.
+       * name-lookup.c (lookup_name_innermost_nonclass_level): 
+       No longer static.
+       * name-lookup.h: Declare it.
+
 2008-01-22  Tom Tromey  <tromey@redhat.com>
 
        PR c++/34829:
index 094501b..ffb0baa 100644 (file)
@@ -526,11 +526,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
index c21940c..ded1d2e 100644 (file)
@@ -43,7 +43,6 @@ struct scope_binding {
 
 static cxx_scope *innermost_nonclass_level (void);
 static cxx_binding *binding_for_name (cxx_scope *, tree);
-static tree lookup_name_innermost_nonclass_level (tree);
 static tree push_overloaded_decl (tree, int, bool);
 static bool lookup_using_namespace (tree, struct scope_binding *, tree,
                                    tree, int);
@@ -4202,7 +4201,7 @@ lookup_type_scope (tree name, tag_scope scope)
 /* Similar to `lookup_name' but look only in the innermost non-class
    binding level.  */
 
-static tree
+tree
 lookup_name_innermost_nonclass_level (tree name)
 {
   struct cp_binding_level *b;
index 7da57be..a4c057e 100644 (file)
@@ -319,6 +319,7 @@ extern bool hidden_name_p (tree);
 extern tree remove_hidden_names (tree);
 extern tree lookup_qualified_name (tree, tree, bool, bool);
 extern tree lookup_name_nonclass (tree);
+extern tree lookup_name_innermost_nonclass_level (tree);
 extern tree lookup_function_nonclass (tree, tree, bool);
 extern void push_local_binding (tree, tree, int);
 extern bool pushdecl_class_level (tree);
diff --git a/gcc/testsuite/g++.dg/lookup/friend12.C b/gcc/testsuite/g++.dg/lookup/friend12.C
new file mode 100644 (file)
index 0000000..95cfd5f
--- /dev/null
@@ -0,0 +1,10 @@
+// PR c++/34912
+
+void foo()
+{
+  struct A
+  {
+    friend void bar();         // { dg-error "without prior declaration" }
+  };
+  bar();                       // { dg-error "not declared" }
+}
index 4fc7e6e..518dd7a 100644 (file)
@@ -9,6 +9,6 @@ void f ()
 {
   class c
     {
-      friend void g () { } // { dg-error "local class definition" "" }
+      friend void g () { } // { dg-error "local class" "" }
     };
 }
index 3a1060a..a783416 100644 (file)
@@ -2,7 +2,7 @@
 void f ()
 {
   struct A {
-    friend void g ();
+    friend void g ();          // { dg-error "without prior declaration" }
   };
 }
 void h () {