2009-01-12 Jason Merrill Steve Ellcey PR c++/35109 * name-lookup.c (lookup_name_real): Keep looking past a hidden binding. * g++.dg/lookup/friend11.C: Remove expected error. * g++.dg/lookup/friend14.C: New test. * g++.dg/lookup/friend15.C: New test. Index: cp/name-lookup.c =================================================================== *** cp/name-lookup.c (revision 143307) --- cp/name-lookup.c (working copy) *************** lookup_name_real (tree name, int prefer_ *** 4118,4133 **** { 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" --- 4118,4142 ---- { if (hidden_name_p (binding)) { ! /* A non namespace-scope binding can only be hidden in the ! presence of a local class, due to friend declarations. ! In particular, consider: + struct C; void f() { struct A { friend struct B; ! friend struct C; ! void g() { ! B* b; // error: B is hidden ! C* c; // OK, finds ::C ! } ! }; ! B *b; // error: B is hidden ! C *c; // OK, finds ::C struct B {}; + B *bb; // OK } The standard says that "B" is a local class in "f" *************** lookup_name_real (tree name, int prefer_ *** 4143,4163 **** 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; --- 4152,4170 ---- 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. 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. ! So just keep looking for a non-hidden binding. ! */ ! gcc_assert (TREE_CODE (binding) == TYPE_DECL); ! continue; } val = binding; break; Index: testsuite/g++.dg/lookup/friend14.C =================================================================== *** testsuite/g++.dg/lookup/friend14.C (revision 0) --- testsuite/g++.dg/lookup/friend14.C (revision 0) *************** *** 0 **** --- 1,17 ---- + // PR c++/35109 + + struct C; + void f() { + struct A { + friend struct B; + friend struct C; + void g() + { + B *b; // { dg-error "not declared" } + C* c; // OK, finds ::C + } + }; + C *c; // OK, finds ::C + struct B {}; + B *b; // OK, now it isn't hidden + } Index: testsuite/g++.dg/lookup/friend11.C =================================================================== *** testsuite/g++.dg/lookup/friend11.C (revision 143307) --- testsuite/g++.dg/lookup/friend11.C (working copy) *************** *** 3,14 **** /* { 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; } --- 3,13 ---- /* { dg-do "compile" } */ class QGList; unsigned count() { class QGListIterator { friend class QGList; ! QGListIterator( const QGList & ); // OK, finds ::QGList. }; return 0; } Index: testsuite/g++.dg/lookup/friend15.C =================================================================== *** testsuite/g++.dg/lookup/friend15.C (revision 0) --- testsuite/g++.dg/lookup/friend15.C (revision 0) *************** *** 0 **** --- 1,12 ---- + // Origin: PR c++/35109 + // { dg-do compile } + + void foo() + { + struct A + { + friend class B; + }; + B::B() {} // { dg-error "has not been declared" } + // { dg-error "expected" "expected" { target *-*-* } 10 } + }