* [Bug c++/32204] friend from global namespace in template class ignored
[not found] <bug-32204-4@http.gcc.gnu.org/bugzilla/>
@ 2011-01-17 6:48 ` jag-gnu at jag dot dreamhost.com
2012-03-26 21:24 ` dpiepgrass at mentoreng dot com
` (7 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: jag-gnu at jag dot dreamhost.com @ 2011-01-17 6:48 UTC (permalink / raw)
To: gcc-bugs
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=32204
jag-gnu at jag dot dreamhost.com changed:
What |Removed |Added
----------------------------------------------------------------------------
CC| |jag-gnu at jag dot
| |dreamhost.com
--- Comment #2 from jag-gnu at jag dot dreamhost.com 2011-01-17 05:37:59 UTC ---
Output of running a recent g++ on the code in comment 0 with cases 2 and 3
commented out:
bug.cpp: In function ‘void f(A::B<int>&)’:
bug.cpp:7: error: ‘int A::B<int>::z’ is private
bug.cpp:10: error: within this context
bug.cpp: In function ‘int main()’:
bug.cpp:14: error: call of overloaded ‘f(A::B<int>&)’ is ambiguous
bug.cpp:10: note: candidates are: void f(A::B<int>&)
bug.cpp:6: note: void A::f(A::B<int>&)
Which clearly shows the compiler thinks there is an A::f, even though case 3
says there isn't.
I suspect the code below has the same problem:
//namespace M { // 1
template <class T> T* makeT() { return new T; }
//}
namespace N {
class Foo {
template <class T> friend T* /*M*/::makeT();
//friend Foo* ::makeT<>(); // 2
Foo() {}
};
}
int main(void)
{
/*M*/::makeT<N::Foo>();
}
bug.cpp: In function ‘T* makeT() [with T = N::Foo]’:
bug.cpp:14: instantiated from here
bug.cpp:9: error: ‘N::Foo::Foo()’ is private
bug.cpp:2: error: within this context
Either 1) putting makeT in a class or namespace, or 2) specializing makeT on
Foo works around the problem.
^ permalink raw reply [flat|nested] 10+ messages in thread
* [Bug c++/32204] friend from global namespace in template class ignored
[not found] <bug-32204-4@http.gcc.gnu.org/bugzilla/>
2011-01-17 6:48 ` [Bug c++/32204] friend from global namespace in template class ignored jag-gnu at jag dot dreamhost.com
@ 2012-03-26 21:24 ` dpiepgrass at mentoreng dot com
2012-03-26 21:32 ` dpiepgrass at mentoreng dot com
` (6 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: dpiepgrass at mentoreng dot com @ 2012-03-26 21:24 UTC (permalink / raw)
To: gcc-bugs
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=32204
David Piepgrass <dpiepgrass at mentoreng dot com> changed:
What |Removed |Added
----------------------------------------------------------------------------
CC| |dpiepgrass at mentoreng dot
| |com
--- Comment #3 from David Piepgrass <dpiepgrass at mentoreng dot com> 2012-03-26 21:20:11 UTC ---
I have run into this bug or a similar bug while porting my code from MSVC to
GCC. I need to declare that a class in the global namespace is a friend of my
template class. However, I discovered that the bug still occurs if no templates
are involved. Here's my repro:
class Friend;
namespace Foo
{
class Base {
};
class Derived : protected Base {
friend class Friend;
};
}
class Friend {
void F(const Foo::Derived* data) const
{
// error: 'Foo::Base' is an inaccessible base of 'Foo::Derived'
const Foo::Base* dataB = data;
}
};
The problem disappears if either (A) Derived is not in a namespace, or (B)
Friend is in a namespace (the forward declaration of Friend is required and, of
course, must be put in the namespace too).
^ permalink raw reply [flat|nested] 10+ messages in thread
* [Bug c++/32204] friend from global namespace in template class ignored
[not found] <bug-32204-4@http.gcc.gnu.org/bugzilla/>
2011-01-17 6:48 ` [Bug c++/32204] friend from global namespace in template class ignored jag-gnu at jag dot dreamhost.com
2012-03-26 21:24 ` dpiepgrass at mentoreng dot com
@ 2012-03-26 21:32 ` dpiepgrass at mentoreng dot com
2012-03-26 23:52 ` redi at gcc dot gnu.org
` (5 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: dpiepgrass at mentoreng dot com @ 2012-03-26 21:32 UTC (permalink / raw)
To: gcc-bugs
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=32204
--- Comment #4 from David Piepgrass <dpiepgrass at mentoreng dot com> 2012-03-26 21:24:26 UTC ---
(In reply to comment #3) I forgot to mention my GCC version, 4.4.3 (the Windows
build that comes with the current Android SDK.)
^ permalink raw reply [flat|nested] 10+ messages in thread
* [Bug c++/32204] friend from global namespace in template class ignored
[not found] <bug-32204-4@http.gcc.gnu.org/bugzilla/>
` (2 preceding siblings ...)
2012-03-26 21:32 ` dpiepgrass at mentoreng dot com
@ 2012-03-26 23:52 ` redi at gcc dot gnu.org
2012-03-27 0:44 ` redi at gcc dot gnu.org
` (4 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: redi at gcc dot gnu.org @ 2012-03-26 23:52 UTC (permalink / raw)
To: gcc-bugs
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=32204
--- Comment #5 from Jonathan Wakely <redi at gcc dot gnu.org> 2012-03-26 23:45:55 UTC ---
(In reply to comment #3)
> I have run into this bug or a similar bug while porting my code from MSVC to
> GCC.
I don't think you have, I think GCC is right to reject your code and MSVC was
wrong to accept it.
> I need to declare that a class in the global namespace is a friend of my
> template class. However, I discovered that the bug still occurs if no templates
> are involved.
Because you haven't hit this bug :)
> Here's my repro:
>
> class Friend;
> namespace Foo
> {
> class Base {
> };
> class Derived : protected Base {
> friend class Friend;
The standard says this declares Friend as a member of the "innermost non-class
scope" which is namespace Foo.
> };
> }
> class Friend {
> void F(const Foo::Derived* data) const
> {
> // error: 'Foo::Base' is an inaccessible base of 'Foo::Derived'
> const Foo::Base* dataB = data;
> }
> };
>
> The problem disappears if either (A) Derived is not in a namespace,
Because then the innermost enclosing non-class scope is the global namespace,
so the same ::Friend class is found.
> or (B)
> Friend is in a namespace (the forward declaration of Friend is required and, of
> course, must be put in the namespace too).
Because then you define the same class as declared by the friend declaration.
To fix your code you should change the friend declaration to refer to ::Friend
friend class ::Friend;
Or in C++11
friend Friend;
In both these forms the friend declaration refers to the already-declared
::Friend rather than declaring a new Foo::Friend class.
^ permalink raw reply [flat|nested] 10+ messages in thread
* [Bug c++/32204] friend from global namespace in template class ignored
[not found] <bug-32204-4@http.gcc.gnu.org/bugzilla/>
` (3 preceding siblings ...)
2012-03-26 23:52 ` redi at gcc dot gnu.org
@ 2012-03-27 0:44 ` redi at gcc dot gnu.org
2012-10-27 8:12 ` scottbaldwin at gmail dot com
` (3 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: redi at gcc dot gnu.org @ 2012-03-27 0:44 UTC (permalink / raw)
To: gcc-bugs
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=32204
Jonathan Wakely <redi at gcc dot gnu.org> changed:
What |Removed |Added
----------------------------------------------------------------------------
Status|NEW |RESOLVED
Known to work| |4.6.3, 4.7.0, 4.8.0
Resolution| |FIXED
Target Milestone|--- |4.6.0
Known to fail| |4.5.1
--- Comment #6 from Jonathan Wakely <redi at gcc dot gnu.org> 2012-03-26 23:51:26 UTC ---
G++ 4.6.0 and later correctly compile this
namespace A { template < class PIX > class B; }
void f(A::B<int>&);
template < class PIX > class A::B {
friend void ::f(A::B<int>&);
PIX z;
};
void f(A::B<int>& i) { int a = i.z; }
int main() {
A::B<int> b;
f(b); // 1. error: f is ambiguous (no, there is no 2nd declaration!)
::f(b); // 2. error: z is private (yes, but 'f' is a friend)
// A::f(b); // 3. error: f is not a member of A (of course)
}
So I think this bug is fixed
^ permalink raw reply [flat|nested] 10+ messages in thread
* [Bug c++/32204] friend from global namespace in template class ignored
[not found] <bug-32204-4@http.gcc.gnu.org/bugzilla/>
` (4 preceding siblings ...)
2012-03-27 0:44 ` redi at gcc dot gnu.org
@ 2012-10-27 8:12 ` scottbaldwin at gmail dot com
2012-10-27 8:52 ` scottbaldwin at gmail dot com
` (2 subsequent siblings)
8 siblings, 0 replies; 10+ messages in thread
From: scottbaldwin at gmail dot com @ 2012-10-27 8:12 UTC (permalink / raw)
To: gcc-bugs
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=32204
etherice <scottbaldwin at gmail dot com> changed:
What |Removed |Added
----------------------------------------------------------------------------
CC| |scottbaldwin at gmail dot
| |com
--- Comment #7 from etherice <scottbaldwin at gmail dot com> 2012-10-27 08:11:45 UTC ---
As Jonathan explains in comment #5, gcc is right to reject this code and MSVC
is wrong to accept it. You will have to add a forward declaration of the
class/function in order to declare it as a friend in the namespaced class. For
example:
// on gcc 4.7.0 (linux), these forward declarations are required for the friend
declarations in ns::NamespacedClass
class GlobalClass;
void globalFunction();
namespace ns {
struct NamespacedClass {
friend ::GlobalClass; // same result whether '::' or 'class' is part of
declaration
friend void ::globalFunction();
private:
NamespacedClass() {}
};
}
struct GlobalClass {
GlobalClass() { ns::NamespacedClass foo; }
};
void globalFunction() {
ns::NamespacedClass foo;
}
^ permalink raw reply [flat|nested] 10+ messages in thread
* [Bug c++/32204] friend from global namespace in template class ignored
[not found] <bug-32204-4@http.gcc.gnu.org/bugzilla/>
` (5 preceding siblings ...)
2012-10-27 8:12 ` scottbaldwin at gmail dot com
@ 2012-10-27 8:52 ` scottbaldwin at gmail dot com
2012-10-27 13:13 ` redi at gcc dot gnu.org
2012-10-27 13:39 ` scottbaldwin at gmail dot com
8 siblings, 0 replies; 10+ messages in thread
From: scottbaldwin at gmail dot com @ 2012-10-27 8:52 UTC (permalink / raw)
To: gcc-bugs
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=32204
--- Comment #8 from etherice <scottbaldwin at gmail dot com> 2012-10-27 08:52:10 UTC ---
In MSVC's defense, the standard is vague (or insufficient) in this regard for
'friend class' declarations. It says:
"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 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."
The standard *should* specify whether the 'friend class declaration' case
applies to qualified names. For example:
namespace ns {
class NSClass {
friend class ::SomeGlobalClass;
};
}
Since ::SomeGlobalClass is qualified (via scope resolution operator) it
explicitly belongs to the global namespace. However, the standard says that it
shall "belong to the innermost enclosing non-class scope", which is a
contradiction (or nonsense). This is why the standard *should* specify a case
for qualified vs unqualified names in friend class declarations (as it does for
normal friend declarations).
The assumption MSVC makes not only seems reasonable, but is also convenient for
developers as it allows *hidden* forward declarations of names in outer
namespaces. This avoids having to make an unnecessary explicit forward
declaration.
Perhaps GCC should "interpret" this part of the standard similarly.
^ permalink raw reply [flat|nested] 10+ messages in thread
* [Bug c++/32204] friend from global namespace in template class ignored
[not found] <bug-32204-4@http.gcc.gnu.org/bugzilla/>
` (6 preceding siblings ...)
2012-10-27 8:52 ` scottbaldwin at gmail dot com
@ 2012-10-27 13:13 ` redi at gcc dot gnu.org
2012-10-27 13:39 ` scottbaldwin at gmail dot com
8 siblings, 0 replies; 10+ messages in thread
From: redi at gcc dot gnu.org @ 2012-10-27 13:13 UTC (permalink / raw)
To: gcc-bugs
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=32204
--- Comment #9 from Jonathan Wakely <redi at gcc dot gnu.org> 2012-10-27 13:13:13 UTC ---
(In reply to comment #8)
> In MSVC's defense, the standard is vague (or insufficient) in this regard for
> 'friend class' declarations. It says:
>
> "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 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."
That wording only applies to local classes, so is irrelevant here. See 7.3.1.2
for the wording that covers non-local classes.
> The standard *should* specify whether the 'friend class declaration' case
> applies to qualified names. For example:
A friend class declaration using qualified name can't introduce a new name, it
can only refer to an existing class, so there must be a prior declaration. See
footnote 95 from 7.3.1.2/3, which says that a friend declaration that first
declares a class must be unqualified.
> namespace ns {
> class NSClass {
> friend class ::SomeGlobalClass;
> };
> }
>
> Since ::SomeGlobalClass is qualified (via scope resolution operator) it
> explicitly belongs to the global namespace.
Yes, but a prior declaration in the global namespace must exist.
> However, the standard says that it
> shall "belong to the innermost enclosing non-class scope", which is a
> contradiction (or nonsense).
No, you've misread the standard.
I think the standard covers your case, GCC behaves correctly here.
This bug report is for a different case anyway, this is not the right place to
discuss it.
^ permalink raw reply [flat|nested] 10+ messages in thread
* [Bug c++/32204] friend from global namespace in template class ignored
[not found] <bug-32204-4@http.gcc.gnu.org/bugzilla/>
` (7 preceding siblings ...)
2012-10-27 13:13 ` redi at gcc dot gnu.org
@ 2012-10-27 13:39 ` scottbaldwin at gmail dot com
8 siblings, 0 replies; 10+ messages in thread
From: scottbaldwin at gmail dot com @ 2012-10-27 13:39 UTC (permalink / raw)
To: gcc-bugs
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=32204
--- Comment #10 from etherice <scottbaldwin at gmail dot com> 2012-10-27 13:39:05 UTC ---
(In reply to comment #9)
Jonathan- You're right on all counts. Thanks for clarifying (and apologies for
getting a bit off-topic).
^ permalink raw reply [flat|nested] 10+ messages in thread