In the process of compiling KDE 3.2 on IRIX 6.5 and Tru64 UNIX 5.1 with the respective vendor C++ compilers, I ran into a namespace issue. Consider the following: $ cat a.h class KMAcctImap; namespace KIO { class Job { public: int b; }; } namespace KMail { class ImapJob { friend class KMAcctImap; public: ImapJob(); private: KIO::Job *mJob; }; } $ cat b.cpp namespace KIO { class Job; } namespace KMail { class ImapJob; } using KMail::ImapJob; class KMAcctImap { friend class KMail::ImapJob; public: void test (void); }; #include "a.h" void KMAcctImap::test (void) { ImapJob *f = new ImapJob (); if (f->mJob) int b; } Compile results with different compilers: (Solaris Sun One 8 compiler) $ CC -c b.cpp "b.cpp", line 22: Error: mJob is not accessible from KMAcctImap::test(). 1 Error(s) detected. (HP-UX C++ compiler) $ aCC -c b.cpp Error 182: "b.cpp", line 22 # "void KMAcctImap::test()" cannot access private member "KIO::Job *KMail::ImapJob::mJob". if (f->mJob) ^^^^^^^ (IRIX C++ compiler) $ CC -c b.cpp cc-1238 CC: ERROR File = b.cpp, Line = 22 The member "KMail::ImapJob::mJob" is inaccessible. if (f->mJob) ^ (IBM C++ compiler) $ xlC -c b.cpp [success] (Tru64 UNIX C++ compiler) $ cxx -c b.cpp cxx: Error: b.cpp, line 22: member "KMail::ImapJob::mJob" is inaccessible if (f->mJob) ---------^ (GCC 3.3.2 with some patches from 3.3.3 merged in) $ g++ -c b.cpp [success] I can cause a successful compile by changing: namespace KMail { class ImapJob { friend class KMAcctImap; to: namespace KMail { class ImapJob { friend class ::KMAcctImap; ^^ Based on http://gcc.gnu.org/ml/gcc/2004-03/msg00499.html, GCC is incorrect.
Confirmed.
OK, so here's what happens: ------------ struct S { void test (void); }; namespace NS { class X { friend class S; static int *i; }; } void S::test () { NS::X::i; } --------------- gcc thinks the 'friend class S' declaration refers to class ::S and thus allows the access in S::test. All the other compilers seem to believe that the friend declaration refer to a yet-to-be-declared class NS::S, and therefore don't allow access in ::S::test. I have yet to understand what the standard really says in this respect. Kriang? W.
Subject: Re: Friend name injection problem (implicit declaration) "bangerth at dealii dot org" <gcc-bugzilla@gcc.gnu.org> writes: | OK, so here's what happens: | ------------ | struct S { | void test (void); | }; | | namespace NS { | class X { | friend class S; | static int *i; | }; | } | | void S::test () { | NS::X::i; | } | --------------- | gcc thinks the 'friend class S' declaration refers to class ::S and thus | allows the access in S::test. All the other compilers seem to believe | that the friend declaration refer to a yet-to-be-declared class NS::S, | and therefore don't allow access in ::S::test. I have yet to understand | what the standard really says in this respect. Kriang? I'm not Kriang but I'm going to answer. Yes, GCC's behaviour is wrong. Compilers that reject the code are right. See the explanation I gave in the link pointed to in the original report. If you want chapter and verse, see somewhere in 7.3.1.x for namespace members that talk about friend declarations. -- Gaby
Looking at friend class injection bugs.
Patches submitted. Both patches are required to fix this bug. http://gcc.gnu.org/ml/gcc-patches/2004-10/msg01321.html http://gcc.gnu.org/ml/gcc-patches/2004-10/msg01372.html
One more patch is required. And libjava problem has to be fixed before this bug is revisited.
Last part is submitted: http://gcc.gnu.org/ml/gcc-patches/2004-11/msg01495.html This one together with earlier parts fix the bug.
Subject: Bug 14513 CVSROOT: /cvs/gcc Module name: gcc Changes by: lerdsuwa@gcc.gnu.org 2004-11-25 16:55:34 Modified files: gcc/cp : ChangeLog name-lookup.c name-lookup.h decl.c cp-tree.h parser.c pt.c rtti.c gcc/testsuite : ChangeLog Added files: gcc/testsuite/g++.dg/lookup: friend2.C gcc/testsuite/g++.dg/template: friend31.C Log message: Friend class name lookup 2/n, PR c++/14513, c++/15410 * name-lookup.c (lookup_name_real): Simplify. (lookup_type_scope): Add SCOPE parameter. Handle friend class lookup. * name-lookup.h (tag_scope): New enum type. (lookup_type_scope): Adjust declaration. * decl.c (lookup_and_check_tag, xref_tag, xref_tag_from_type): Change bool parameter GLOBALIZED to TAG_SCOPE parameter SCOPE. (start_enum): Likewise. Add assertion test that NAME is IDENTIFIER_NODE. Use anonymous name for dummy ENUMERAL_TYPE in case of error. * cp-tree.h (xref_tag, xref_tag_from_type): Adjust declarations. * parser.c (cp_parser_elaborated_type_specifier, cp_parser_class_head): Adjust call to xref_tag. * pt.c (lookup_template_class, instantiate_class_template): Likewise. * rtti.c (init_rtti_processing, build_dynamic_cast_1, tinfo_base_init, emit_support_tinfos): Likewise. * g++.dg/lookup/friend2.C: New test. * g++.dg/template/friend31.C: Likewise. Patches: http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/ChangeLog.diff?cvsroot=gcc&r1=1.4496&r2=1.4497 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/name-lookup.c.diff?cvsroot=gcc&r1=1.93&r2=1.94 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/name-lookup.h.diff?cvsroot=gcc&r1=1.30&r2=1.31 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/decl.c.diff?cvsroot=gcc&r1=1.1332&r2=1.1333 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/cp-tree.h.diff?cvsroot=gcc&r1=1.1072&r2=1.1073 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/parser.c.diff?cvsroot=gcc&r1=1.281&r2=1.282 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/pt.c.diff?cvsroot=gcc&r1=1.947&r2=1.948 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/rtti.c.diff?cvsroot=gcc&r1=1.203&r2=1.204 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/ChangeLog.diff?cvsroot=gcc&r1=1.4646&r2=1.4647 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.dg/lookup/friend2.C.diff?cvsroot=gcc&r1=NONE&r2=1.1 http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.dg/template/friend31.C.diff?cvsroot=gcc&r1=NONE&r2=1.1
Fixed in the mainline.
*** Bug 19403 has been marked as a duplicate of this bug. ***
Kriang, would you please add a note to changes.html about this? I am sure it is going to surprise many many people.
It is already described in changes.html: When declaring a friend class using an unqualified name, classes outside the innermost non-class scope are not searched ...