User account creation filtered due to spam.

Bug 13495 - Friendship to class nested within a template is broken
Summary: Friendship to class nested within a template is broken
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 3.4.0
: P2 minor
Target Milestone: 4.0.0
Assignee: Kriang Lerdsuwanakij
URL:
Keywords: accepts-invalid, patch, rejects-valid
Depends on: 16617
Blocks:
  Show dependency treegraph
 
Reported: 2003-12-27 02:22 UTC by Stefan Straßer
Modified: 2004-10-20 16:25 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2004-08-16 18:22:43


Attachments
Patch that gets `template <class T> friend class A<T>::B;' to be accepted (742 bytes, patch)
2004-08-06 19:30 UTC, Alexandre Oliva
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Stefan Straßer 2003-12-27 02:22:37 UTC
Hi.
I don´t exactly know what the correct syntax to do this is, since I couldn´t
look up in the specification, but it looks like a bug because
a) I couldn´t figure out a way to do this with GCC
b) I could figure out a way which does work with MSVC but doesn´t with GCC

so here it is:

a template class which contains a nested class which itself is no template but
inherits the template parameter:

template<typename T>
class A{
public:
  class B{};
};

class A<T>::B should be friend of another class:

template<typename T>
class OtherClass{
  XXX
};

A<T>::B is a dependent type, so using it requires the 'typename'-keyword.
("implicit typename deprecated")

a) XXX == friend typename A<T>::B; doesn´t work because it requires the
'class'-keyword because it´s a class friendship

b) XXX == friend class A<T>::B; doesn´t work because A<T>::B is a dependent
typename, which requires the 'typename' keyword.

c) XXX == friend typename class A<T>::B; or 
d) XXX == friend class typename A<T>::B pass out with parse error.

MSVC compiles a) (wrongly) and c) (possibly correct)

Thank you,

Stefan
Comment 1 Giovanni Bajo 2003-12-27 09:03:39 UTC
It's been clarified by DR180 that the form:

friend class A<T>::B;

is the only allowed. In fact, the name is implicitily a type because of 
the 'class' keyword put in front of it, so a typename is not needed (and it is 
not allowed by syntax either). This has been correctly implemented by the new 
parser in GCC 3.4.

Then you must understand the difference between:

template<class T> class OtherClass {
   friend class A<T>::B;
};

and:

template<class T> class OtherClass {
   template <class Q>
   friend class A<Q>::B;
};

In the first case, you're saying that, for each OtherClass<X>, A<X>::B is a 
friend (only for the same X!). In the second, you're saying that for each 
OtherClass<X>, any A<Y>::B is a friend (for any Y).

Nonetheless, there is indeed a bug in GCC. I propose this testcase:

--------------------------------------------
template<typename T>
class A{
public:
    class B
    {
        void func1(void);
        void func2(void);
    };
};

template<typename Q>
class F1
{
    friend class A<Q>::B;
    enum { foo = 0 };
};

template<typename Q>
class F2
{
    template<typename T>
    friend class A<T>::B;
    enum { foo = 0 };
};

template <typename T>
void A<T>::B::func1(void)
{
    (void)F1<T>::foo;        // OK, A<T>::B is a friend for this T (#1)
    (void)F2<T>::foo;        // OK, any A<K>::B is a friend (#2)
}

template <typename T>
void A<T>::B::func2(void)
{
    (void)F1<double>::foo;   // ERROR, A<double>::T is not a friend (#3)
    (void)F2<double>::foo;   // OK, any A<K>::B is a friend (#4)
}

template class A<void>;
--------------------------------------------

Thus, GCC should emit an error only for #3. Instead it emits an error for #2 
and not for #3. This is clearly a bug (but not a regression, since the previous 
versions of GCC were even more broken wrt friendships to nested classes or 
specializations of templates).

This is a job for Kriang :)
Comment 2 Alexandre Oliva 2004-08-06 19:30:41 UTC
Created attachment 6895 [details]
Patch that gets `template <class T> friend class A<T>::B;' to be accepted

In case there's interest, this patch (written for 3.2.3; might still apply to
3.3) is implemented to enable the compiler to parse `template <class T> friend
class A<T>::B;' correctly.  So far I've only verified the fix on 3.2.3, and I
haven't tested it any further than that, but if there's interest in integrating
a fix for this problem in GCC 3.3, feel free to pick the patch up from this
point.
Comment 3 Giovanni Bajo 2004-08-30 15:33:29 UTC
Kriang, it looks like g++.old-deja/g++.pt/friend44.C is related to this bug. 
The testcase is xfailed on mainline, and you already fixed half of it with your 
patch for PR5369. I guess your patch for this bug also cures that testcase?
Comment 4 Kriang Lerdsuwanakij 2004-08-31 10:56:26 UTC
Yes, the patch will also fix the warning produced
when testing g++.old-deja/g++.pt/friend44.C.
Comment 5 Kriang Lerdsuwanakij 2004-09-04 15:59:12 UTC
Patch in progress.  Note that even with the fix,
GCC still doesn't diagnose the code in Comment #1
correctly because of PR16617.
Comment 6 Kriang Lerdsuwanakij 2004-09-06 15:55:59 UTC
Patch submitted:
  http://gcc.gnu.org/ml/gcc-patches/2004-09/msg00557.html
Comment 7 CVS Commits 2004-10-20 16:20:59 UTC
Subject: Bug 13495

CVSROOT:	/cvs/gcc
Module name:	gcc
Changes by:	lerdsuwa@gcc.gnu.org	2004-10-20 16:20:51

Modified files:
	gcc/cp         : ChangeLog cp-tree.h decl.c friend.c parser.c 
	                 pt.c 
	gcc/testsuite  : ChangeLog 
	gcc/testsuite/g++.old-deja/g++.pt: friend44.C 
Added files:
	gcc/testsuite/g++.dg/template: memfriend9.C memfriend10.C 
	                               memfriend11.C memfriend12.C 
	                               memfriend13.C memfriend14.C 
	                               memfriend15.C memfriend16.C 
	                               memfriend17.C 

Log message:
	PR c++/13495
	* decl.c (make_unbound_class_template): Add PARM_LIST parameter.
	* cp-tree.h (make_unbound_class_template): Adjust prototype.
	* parser.c (cp_parser_lookup_name): Adjust call to
	make_unbound_class_template.
	(cp_parser_single_declaration): Handle member class of class
	template as template friend parsing correctly.
	* friend.c (is_friend): Call is_specialization_of_friend for
	template friend class.
	(make_friend_class): Handle member class of class template as
	template friend.
	* pt.c (is_specialization_of_friend): Likewise.
	(instantiate_class_template): Likewise.
	(tsubst): Adjust call to make_unbound_class_template.
	
	* g++.dg/template/memfriend9.C: New test.
	* g++.dg/template/memfriend10.C: Likewise.
	* g++.dg/template/memfriend11.C: Likewise.
	* g++.dg/template/memfriend12.C: Likewise.
	* g++.dg/template/memfriend13.C: Likewise.
	* g++.dg/template/memfriend14.C: Likewise.
	* g++.dg/template/memfriend15.C: Likewise.
	* g++.dg/template/memfriend16.C: Likewise.
	* g++.dg/template/memfriend17.C: Likewise.
	* g++.old-deja/g++.pt/friend44.C: Remove bogus error.

Patches:
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/ChangeLog.diff?cvsroot=gcc&r1=1.4447&r2=1.4448
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/cp-tree.h.diff?cvsroot=gcc&r1=1.1065&r2=1.1066
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/decl.c.diff?cvsroot=gcc&r1=1.1316&r2=1.1317
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/friend.c.diff?cvsroot=gcc&r1=1.101&r2=1.102
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/parser.c.diff?cvsroot=gcc&r1=1.267&r2=1.268
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/pt.c.diff?cvsroot=gcc&r1=1.936&r2=1.937
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/ChangeLog.diff?cvsroot=gcc&r1=1.4478&r2=1.4479
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.dg/template/memfriend9.C.diff?cvsroot=gcc&r1=NONE&r2=1.1
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.dg/template/memfriend10.C.diff?cvsroot=gcc&r1=NONE&r2=1.1
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.dg/template/memfriend11.C.diff?cvsroot=gcc&r1=NONE&r2=1.1
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.dg/template/memfriend12.C.diff?cvsroot=gcc&r1=NONE&r2=1.1
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.dg/template/memfriend13.C.diff?cvsroot=gcc&r1=NONE&r2=1.1
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.dg/template/memfriend14.C.diff?cvsroot=gcc&r1=NONE&r2=1.1
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.dg/template/memfriend15.C.diff?cvsroot=gcc&r1=NONE&r2=1.1
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.dg/template/memfriend16.C.diff?cvsroot=gcc&r1=NONE&r2=1.1
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.dg/template/memfriend17.C.diff?cvsroot=gcc&r1=NONE&r2=1.1
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.old-deja/g++.pt/friend44.C.diff?cvsroot=gcc&r1=1.3&r2=1.4

Comment 8 Kriang Lerdsuwanakij 2004-10-20 16:25:46 UTC
I am closing this as fixed by patch:
  http://gcc.gnu.org/ml/gcc-patches/2004-10/msg01709.html

For access checking problem mentioned in the comments, it's 
already covered in PR16617.  That part requires some structural 
changes that won't be investigated for some time.