public inbox for gcc-bugs@sourceware.org
help / color / mirror / Atom feed
* [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

* [Bug c++/32204] friend from global namespace in template class ignored
  2007-06-04 12:01 [Bug c++/32204] New: " klaus dot kretschel at dlr dot de
@ 2009-12-08 23:11 ` redi at gcc dot gnu dot org
  0 siblings, 0 replies; 10+ messages in thread
From: redi at gcc dot gnu dot org @ 2009-12-08 23:11 UTC (permalink / raw)
  To: gcc-bugs



------- Comment #1 from redi at gcc dot gnu dot org  2009-12-08 23:11 -------
Confirmed, the friend declaration appears to be declaring f in namespace A,
despite the :: qualifier


-- 

redi at gcc dot gnu dot org changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|UNCONFIRMED                 |NEW
     Ever Confirmed|0                           |1
      Known to fail|                            |4.4.2
   Last reconfirmed|0000-00-00 00:00:00         |2009-12-08 23:11:05
               date|                            |


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=32204


^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2012-10-27 13:39 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [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
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
2012-10-27 13:13 ` redi at gcc dot gnu.org
2012-10-27 13:39 ` scottbaldwin at gmail dot com
2007-06-04 12:01 [Bug c++/32204] New: " klaus dot kretschel at dlr dot de
2009-12-08 23:11 ` [Bug c++/32204] " redi at gcc dot gnu dot org

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).