Bug 15664 - Template friend injection fails
Summary: Template friend injection fails
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 3.4.0
: P2 normal
Target Milestone: 4.0.0
Assignee: Kriang Lerdsuwanakij
URL:
Keywords: patch, rejects-valid
Depends on:
Blocks: 12944 16995
  Show dependency treegraph
 
Reported: 2004-05-26 18:55 UTC by Ivan Godard
Modified: 2004-12-02 12:02 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail: 2.95.3 3.3.4 3.4.0
Last reconfirmed: 2004-05-26 20:56:41


Attachments
Compiler output (-v -save-temps) (870 bytes, text/plain)
2004-05-26 18:56 UTC, Ivan Godard
Details
Source code (-save-temps) (111.81 KB, text/plain)
2004-05-26 18:57 UTC, Ivan Godard
Details
Compiler output (-v -save-temps) - 3 args (847 bytes, text/plain)
2004-05-26 19:55 UTC, Ivan Godard
Details
Source code (-save-temps) - 3 args (111.82 KB, text/plain)
2004-05-26 19:56 UTC, Ivan Godard
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Ivan Godard 2004-05-26 18:55:38 UTC
Linker doesn't find operator==(class, class). The definition of the operator is "inline", but removing that doesn't help. Problem occurs in both -O0 and -O2, consistent with inline not important. Operator is declared, then redeclared as a friend, then defined. The definition finds the friend (comment out friend gives syntax errors on invisibles in the definition). The first declaration is not needed; no change if it is commented out. I suspect an error in name mangling, as the operator has a complicated type with two template templates, but the type listed in the error message seems correct.
Comment 1 Ivan Godard 2004-05-26 18:56:22 UTC
Created attachment 6386 [details]
Compiler output (-v -save-temps)
Comment 2 Ivan Godard 2004-05-26 18:57:42 UTC
Created attachment 6387 [details]
Source code (-save-temps)
Comment 3 Ivan Godard 2004-05-26 19:07:53 UTC
More info: if the friend declaration is removed (with everything necessary made public so the definition compiles) then the problem goes away. This suggests that the compiler is generating a reference to the friend somehow, and not considering the definition to be the same as the friend. Odd.
Comment 4 Wolfgang Bangerth 2004-05-26 19:21:14 UTC
Your code looks like this: 
------------------- 
template<typename E, template<typename>class A1, template<typename>class A2> 
bool operator==(const Powerbase<E, A1>& p1, const Powerbase<E, A2>& p2); 
 
template<typename E, template<typename> class Alloc> 
class Powerbase 
{ 
    template<template<typename>class A2> 
    friend 
    bool operator==(const Powerbase<E, Alloc>& p1, 
                    const Powerbase<E, A2>& p2); 
}; 
 
template<typename E, template<typename> class A1, template<typename>class A2> 
inline 
bool operator==(const Powerbase<E, A1>& p1, 
                const Powerbase<E, A2>& p2) { 
  return p1.Relop(p2, Powerbase<E, A1>::equalOp); 
} 
------------------------- 
The problem with it is that the friend declaration is not for the function 
you have previously declared (easily seen by the fact that it has only one 
instead of three template arguments). Thus, the compiler assumes that it 
is a previously undeclared overload of operator== and injects it into the 
global namespace. You therefore have two overloaded declarations, and the 
compiler later on in the program happens to pick the one that was 
declared in the friend declaration. It doesn't exist, though, thus the 
linker error. 
 
The general rule is: since there are no partial specializations for template 
functions, the only thing you can declare a friend is a general template, 
in this case the three-argument template. You can't declare only certain 
possible instantiations of a template a friend. 
 
W. 
Comment 5 Ivan Godard 2004-05-26 19:54:36 UTC
Thanks for the explanation - they do help. Unfortunately I had already used the three-argument form and gotten compile errors. With experimentation I found that the one-argument form at least compiled though it wouldn't link. Herewith are the 3-argument results.
Comment 6 Ivan Godard 2004-05-26 19:55:26 UTC
Created attachment 6388 [details]
Compiler output (-v -save-temps) - 3 args
Comment 7 Ivan Godard 2004-05-26 19:56:42 UTC
Created attachment 6389 [details]
Source code (-save-temps) - 3 args
Comment 8 Wolfgang Bangerth 2004-05-26 20:56:38 UTC
Alright, that's better. I think this actually shows a gcc bug: 
------------------ 
template <int N> struct S { 
    template<template<typename> class A> 
    friend void foo(); 
}; 
 
template<template<typename> class A> 
void foo(); 
 
template <typename> struct X {}; 
 
int main () { 
  S<1> s; 
  foo<X>(); 
} 
------------------- 
The friend declaration should inject the name into the global namespace, 
and it should be identified with the other declaration. However, we get 
this: 
 
g/x> /home/bangerth/bin/gcc-3.3.4-pre/bin/c++ -c x.cc 
x.cc: In function `int main()': 
x.cc:13: error: call of overloaded `foo()' is ambiguous 
x.cc:7: error: candidates are: void foo() [with A = X] 
x.cc:3: error:                 void foo() [with A = X, int N = 1] 
 
(Note also that the last line is pretty bad, since it lists the 
template argument to the enclosing class, which, however, isn't 
specified at all in the rest of the line.) Interestingly enough, 
the error goes away if  
a) S is made a non-template 
b) foo takes as template argument not a template template parameter, 
   but a regular type or value 
 
May someone else try to figure out from this what's going wrong. 
 
This bug is on all versions of gcc. 
 
W. 
Comment 9 Giovanni Bajo 2004-05-27 08:36:42 UTC
Confirmed, and this is the Nth bug of ours about friend name injection...
Comment 10 Kriang Lerdsuwanakij 2004-11-11 12:44:29 UTC
A template template parameter bug, probably a duplicate of PR18276.
Comment 11 Kriang Lerdsuwanakij 2004-11-12 16:58:18 UTC
Patch submitted:
  http://gcc.gnu.org/ml/gcc-patches/2004-11/msg00971.html
Comment 12 CVS Commits 2004-12-02 12:00:53 UTC
Subject: Bug 15664

CVSROOT:	/cvs/gcc
Module name:	gcc
Changes by:	lerdsuwa@gcc.gnu.org	2004-12-02 12:00:44

Modified files:
	gcc/cp         : ChangeLog pt.c 
	gcc/testsuite  : ChangeLog 
Added files:
	gcc/testsuite/g++.dg/template: ttp13.C ttp14.C 

Log message:
	PR c++/15664, c++/18276
	* pt.c (tsubst_decl) <TEMPLATE_DECL case>: Reorganize.  Correctly
	tsubst TEMPLATE_DECL that is a TEMPLATE_TEMPLATE_PARM.
	
	* g++.dg/template/ttp13.C: New test.
	* g++.dg/template/ttp14.C: Likewise.

Patches:
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/ChangeLog.diff?cvsroot=gcc&r1=1.4510&r2=1.4511
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/cp/pt.c.diff?cvsroot=gcc&r1=1.952&r2=1.953
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/ChangeLog.diff?cvsroot=gcc&r1=1.4706&r2=1.4707
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.dg/template/ttp13.C.diff?cvsroot=gcc&r1=NONE&r2=1.1
http://gcc.gnu.org/cgi-bin/cvsweb.cgi/gcc/gcc/testsuite/g++.dg/template/ttp14.C.diff?cvsroot=gcc&r1=NONE&r2=1.1

Comment 13 Kriang Lerdsuwanakij 2004-12-02 12:02:40 UTC
Fixed in the mainline.