]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR c++/30917 (ICE with friend in local class (to a function))
authorSimon Martin <simartin@users.sourceforge.net>
Sat, 28 Jul 2007 20:12:42 +0000 (20:12 +0000)
committerSimon Martin <simartin@gcc.gnu.org>
Sat, 28 Jul 2007 20:12:42 +0000 (20:12 +0000)
gcc/cp/

2007-07-28  Simon Martin  <simartin@users.sourceforge.net>
            Mark Mitchell  <mark@codesourcery.com>

        PR c++/30917
        * name-lookup.c (lookup_name_real): Non namespace-scope bindings can be
        hidden due to friend declarations in local classes.

gcc/testsuite/

2007-07-28  Simon Martin  <simartin@users.sourceforge.net>

        PR c++/30917
        * g++.dg/lookup/friend11.C: New test.

Co-Authored-By: Mark Mitchell <mark@codesourcery.com>
From-SVN: r127023

gcc/cp/ChangeLog
gcc/cp/name-lookup.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/lookup/friend11.C [new file with mode: 0644]

index 9be0feb488f01ca9deca2adba0f60bfd0922956f..50bff48ec6cef4858a26e28d8a8397cd97dccef9 100644 (file)
@@ -1,3 +1,10 @@
+2007-07-28  Simon Martin  <simartin@users.sourceforge.net>
+           Mark Mitchell  <mark@codesourcery.com>
+
+       PR c++/30917
+       * name-lookup.c (lookup_name_real): Non namespace-scope bindings can be
+       hidden due to friend declarations in local classes.
+
 2007-07-27  Mark Mitchell  <mark@codesourcery.com>
 
        PR c++/32346
index 3016bb0ad560b4015a24381d0a019865eea72279..b0358479b56edbd01c64aadddd4736a90d1e357d 100644 (file)
@@ -3996,8 +3996,49 @@ lookup_name_real (tree name, int prefer_type, int nonclass, bool block_p,
 
        if (binding)
          {
-           /* Only namespace-scope bindings can be hidden.  */
-           gcc_assert (!hidden_name_p (binding));
+           if (hidden_name_p (binding))
+             {
+               /* A non namespace-scope binding can only be hidden if
+                  we are in a local class, due to friend declarations.
+                  In particular, consider:
+
+                  void f() {
+                    struct A {
+                      friend struct B;
+                      void g() { B* b; } // error: B is hidden
+                    }
+                    struct B {};
+                  }
+
+                  The standard says that "B" is a local class in "f"
+                  (but not nested within "A") -- but that name lookup
+                  for "B" does not find this declaration until it is
+                  declared directly with "f".
+
+                  In particular:
+
+                  [class.friend]
+
+                  If a friend declaration appears in a local class 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 class declaration, if there is no
+                  prior declaration, the class that is specified 
+                  belongs to the innermost enclosing non-class scope,
+                  but if it is subsequently referenced, its name is not
+                  found by name lookup until a matching declaration is
+                  provided in the innermost enclosing nonclass scope.
+               */
+               gcc_assert (current_class_type &&
+                           LOCAL_CLASS_P (current_class_type));
+
+               /* This binding comes from a friend declaration in the local
+                  class. The standard (11.4.8) states that the lookup can
+                  only succeed if there is a non-hidden declaration in the
+                  current scope, which is not the case here.  */
+               POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, NULL_TREE);
+             }
            val = binding;
            break;
          }
index e6947a64201df185895d91a562018a7aaf91b9b6..8372068f7780d509d02c79c3cd6fe1a2a4f474ef 100644 (file)
@@ -1,3 +1,8 @@
+2007-07-28  Simon Martin  <simartin@users.sourceforge.net>
+
+       PR c++/30917
+       * g++.dg/lookup/friend11.C: New test.
+
 2007-07-27  Mark Mitchell  <mark@codesourcery.com>
 
        PR c++/32346
diff --git a/gcc/testsuite/g++.dg/lookup/friend11.C b/gcc/testsuite/g++.dg/lookup/friend11.C
new file mode 100644 (file)
index 0000000..ab8a9e5
--- /dev/null
@@ -0,0 +1,24 @@
+/* PR c++/30917 */
+/* This used to ICE */
+/* { dg-do "compile" } */
+
+
+// This is invalid: QGList must only be looked up in count.
+class QGList;
+unsigned count() {
+  class QGListIterator {
+    friend class QGList;
+    QGListIterator( const QGList & ); /* { dg-error "expected|with no type" } */
+  };
+  return 0;
+}
+
+// This is valid.
+unsigned count2() {
+  class QGList2;
+  class QGListIterator2 {
+    friend class QGList2;
+    QGListIterator2( const QGList2 & );
+  };
+  return 0;
+}