From eca1687b9c84504d19fe99c16f4779b740e28b11 Mon Sep 17 00:00:00 2001 From: simartin Date: Sat, 28 Jul 2007 10:48:30 +0000 Subject: gcc/cp/ 2007-07-28 Simon Martin Mark Mitchell 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 PR c++/30917 * g++.dg/lookup/friend11.C: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@127016 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/cp/ChangeLog | 7 ++++++ gcc/cp/name-lookup.c | 45 ++++++++++++++++++++++++++++++++-- gcc/testsuite/ChangeLog | 5 ++++ gcc/testsuite/g++.dg/lookup/friend11.C | 24 ++++++++++++++++++ 4 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/g++.dg/lookup/friend11.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 51412983ee0..57c1e413fd2 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,10 @@ +2007-07-28 Simon Martin + Mark Mitchell + + 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 Douglas Gregor * typeck.c (structural_comptypes): Compare DECLTYPE_TYPE nodes. diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index 068725859ff..81466381939 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -3990,8 +3990,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; } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 5352bce536d..52e0b5e43ed 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2007-07-28 Simon Martin + + PR c++/30917 + * g++.dg/lookup/friend11.C: New test. + 2007-07-28 Daniel Franke * gfortran.dg/namelist_5.f90: Adjusted error message. diff --git a/gcc/testsuite/g++.dg/lookup/friend11.C b/gcc/testsuite/g++.dg/lookup/friend11.C new file mode 100644 index 00000000000..ab8a9e50736 --- /dev/null +++ b/gcc/testsuite/g++.dg/lookup/friend11.C @@ -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; +} -- cgit v1.2.1