[Bug c++/53573] New: template type dependant name resolution broken
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53573 Bug #: 53573 Summary: template type dependant name resolution broken Classification: Unclassified Product: gcc Version: 4.7.0 Status: UNCONFIRMED Severity: major Priority: P3 Component: c++ AssignedTo: unassig...@gcc.gnu.org ReportedBy: ke...@fry-it.com
[Bug c++/53573] template type dependant name resolution broken
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53573 Keean Schupke changed: What|Removed |Added CC||ke...@fry-it.com --- Comment #1 from Keean Schupke 2012-06-04 13:30:59 UTC --- // test.cpp // // gcc-version: gcc (Gentoo 4.7.0 p1.0, pie-0.5.3) 4.7.0 // system-type: Linux Ra 3.0.29-tuxonice #4 SMP PREEMPT //Sat May 26 10:21:39 BST 2012 //x86_64 Genuine Intel(R) CPU U7300 @ 1.30GHz GenuineIntel GNU/Linux // compile options: g++ test.cpp // compile output: //test.cpp: In instantiation of ‘T f(T) [with T = int]’: //test.cpp:27:9: required from here //test.cpp:18:12: error: ‘g’ was not declared in this scope, //and no declarations were found by argument-dependent lookup //at the point of instantiation [-fpermissive] //test.cpp:21:5: note: ‘int g(int)’ declared here, later in the //translation unit template T f(T t) { return g(t); } int g(int x) { return x + 1; } main() { int x(1); x = f(x); }
[Bug c++/53573] template type dependant name resolution broken
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53573 --- Comment #2 from Keean Schupke 2012-06-04 13:33:38 UTC --- The function called in the template definition is clearly dependent on the template parameter 'T' and therefore itsname should be resolved at the point of instantiation where 'g' is clearly defined and in scope (and is not local). The error message says: "no declarations were found by argument-dependent lookup at the point of instantiation" when 'g' should be found. See Technicalities C.13.8
[Bug c++/53573] template type dependent name resolution broken
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53573 --- Comment #3 from Keean Schupke 2012-06-04 13:44:14 UTC --- From: Technicalities C.13.8.3: " struct X { X(int); /* ... */ }; " " void g(X); " " template void f(T a) { g(a); } " " void h() " { " extern void g(int); " f(2); // invokes f(X(2)); that is, f(X(2)) " } " " Here, the point of instantiation for f is just before h()... Note: just before "h()", not just before "template"
[Bug c++/53573] template type dependent name resolution broken
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53573 --- Comment #4 from Keean Schupke 2012-06-04 16:38:21 UTC --- From C++ Standard N3242=11-0012 14.6 Name Resolution 10. If a name does not depend on a template-parameter (as defined in 14.6.2), a declaration (or set of declarations) for that name shall be in scope at the point where the name appears in the template definition; the name is bound to the declaration (or declarations) found at that point and this binding is not affected by declarations that are visible at the point of instantiation. [Example: void f(char); template void g(T t) { f(1); // f(char) f(T(1)); // dependent f(t); // dependent dd++; // not dependent // error: declaration for dd not found } enum E { e }; void f(E); double dd; void h() { g(e); // will cause one call of f(char) followed // by two calls of f(E) g(’a’); // will cause three calls of f(char) } — end example ]
[Bug c++/53573] template type dependent name resolution broken
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53573 --- Comment #5 from Keean Schupke 2012-06-04 17:13:18 UTC --- The following program will apparently compile correctly, but will silently produce incorrect results at runtime: #include char g(char x) { return x - 1; } template T f(T t) { return g(t); } int g(int x) { return x + 1; } main() { int x(1); int y(f(x)); std::cout << y << "\n"; int z(f(x)); std::cout << z << "\n"; } This should print "2 2" but prints "0 0". Interestingly it also produces incorrect results with gcc-4.6.3 and gcc-4.5.3. However the code below (which does not compile on gcc-4.7.0 does produce the correct results on gcc-4.6.3 and gcc-4.5.3: #include template T f(T t) { return g(t); } char g(char x) { return x - 1; } int g(int x) { return x + 1; } main() { int x(1); int y(f(x)); std::cout << y << "\n"; int z(f(x)); std::cout << z << "\n"; } So it looks like earlier versions of GCC relied on 'g' being undefined at the point of definition to defer binding until instantiation instead of looking for dependence on a template parameter. gcc-4.7.0 does not seem to do either. One more example: #include class A {}; A g(A x) { return x; } template T f(T t) { return g(t); } int g(int x) { return x + 1; } main() { int x(1); int y(f(x)); std::cout << y << "\n"; int z(f(x)); std::cout << z << "\n"; } generates the following compile error: test.cpp: In function ‘T f(T) [with T = int]’: test.cpp:35:11: instantiated from here test.cpp:26:12: error: could not convert ‘t’ from ‘int’ to ‘A’
[Bug c++/53573] template type dependent name resolution broken
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53573 --- Comment #6 from Keean Schupke 2012-06-05 09:06:01 UTC --- The suggested work around in the error message 'adding -fpermissive' to gcc-4.7.0 does not fix the problem as suggested by the error message. This would suggest the compiler is not displaying the correct error message for the problem. g++ -fpermissive test.cpp Still generates: test.cpp: In instantiation of ‘T f(T) [with T = int]’: test.cpp:27:9: required from here test.cpp:18:12: error: ‘g’ was not declared in this scope, and no declarations were found by argument-dependent lookup at the point of instantiation [-fpermissive] test.cpp:21:5: note: ‘int g(int)’ declared here, later in the translation unit A further test: int g(int x) { return x + 1; } char g(char x) { return x - 1; } template T f(T t) { return g((T)t); } double g(double x) { return x; } main() { double x(f(1.0L)); } generates the following compile time error: test.cpp: In instantiation of ‘T f(T) [with T = long double]’: test.cpp:18:17: required from here test.cpp:10:15: error: call of overloaded ‘g(long double)’ is ambiguous test.cpp:10:15: note: candidates are: test.cpp:1:5: note: int g(int) test.cpp:5:6: note: char g(char) Which is interesting as it suggests that the overloading of 'g' is happening from the definitions of 'g' that are in scope at the template definition. This is quite strange behaviour, as the compiler must have to capture a list all available overloads at the time of definition of each template. This looks like a deliberate behaviour rather than a bug. So this looks more like a misunderstanding of the specification is the cause of this incorrect behaviour?
[Bug c++/53573] template type dependent name resolution broken
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53573 --- Comment #8 from Keean Schupke 2012-06-05 10:15:18 UTC --- (In reply to comment #7) Have a read of the C++ standard, the example given in: N3242=11-0012 14.6 Name Resolution: paragraph 10 Which I have pasted above into comment #4 and the extract from C++ Special Edition (Technicalities C.13.8.3) which is pasted in comment #3. How do you interpret these two? > (In reply to comment #6) > > The suggested work around in the error message 'adding -fpermissive' to > > gcc-4.7.0 does not fix the problem as suggested by the error message. This > > would suggest the compiler is not displaying the correct error message for > > the > > problem. > > > > g++ -fpermissive test.cpp > > > > Still generates: > > > > test.cpp: In instantiation of ‘T f(T) [with T = int]’: > > test.cpp:27:9: required from here > > test.cpp:18:12: error: ‘g’ was not declared in this scope, and no > > declarations > > were found by argument-dependent lookup at the point of instantiation > > [-fpermissive] > > test.cpp:21:5: note: ‘int g(int)’ declared here, later in the translation > > unit > > > > With GCC 4.8 revision 187148, -fpermissive generates a warning as it should. > However, -fpermissive is not meant to fix anything, it is just a work-around > to > make non-standard code compile. > > I am not sure if this is a bug or not, so I am not touching the status.
[Bug c++/53573] template type dependent name resolution broken
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53573 --- Comment #11 from Keean Schupke 2012-06-05 11:07:14 UTC --- (In reply to comment #9) Can you point me at where in the specification this is defined? > (In reply to comment #2) > > The function called in the template definition is clearly dependent on the > > template parameter 'T' and therefore itsname should be resolved at the > > point of > > instantiation where 'g' is clearly defined and in scope (and is not local). > > The > > error message says: "no declarations were found by argument-dependent > > lookup at > > the point of instantiation" when 'g' should be found. > > Built-in types have no associated namespaces so ADL can not find 'g' via ADL. > A > declaration must be visible at the point of definition. > > The example in comment 1 is ill-formed. > > Paragraph 10 doesn't apply because the call is clearly dependent. > > N.B. N3242 is not the C++ standard and neither is "C++ Special Edition" which > is quite old now.
[Bug c++/53573] template type dependent name resolution broken
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53573 --- Comment #12 from Keean Schupke 2012-06-05 11:14:00 UTC --- (In reply to comment #10) although -fpermissive allows the code to compile (in some circumstances) it does not in all, and it also produces incorrect output, for example: #include char g(char x) { return x - 1; } template T f(T t) { return g(t); } double g(double x) { return x; } main() { double x(f(1.0L)); std::cout << x << "\n"; } will output "0" instead of "1" choosing the wrong overloaded function. In the case below: #include char g(char x) { return x - 1; } int g(int x) { return x + 1; } template T f(T t) { return g(t); } double g(double x) { return x; } main() { double x(f(1.0L)); std::cout << x << "\n"; } compilation still fails with: test.cpp: In instantiation of ‘T f(T) [with T = long double]’: test.cpp:20:17: required from here test.cpp:12:12: error: call of overloaded ‘g(long double&)’ is ambiguous test.cpp:12:12: note: candidates are: test.cpp:3:6: note: char g(char) test.cpp:7:5: note: int g(int) even with -fpermissive > (In reply to comment #6) > > The suggested work around in the error message 'adding -fpermissive' to > > gcc-4.7.0 does not fix the problem as suggested by the error message. > > As Manu says, -fpermissive changes the error to a warning, allowing the code > to > compile. Please check it again. > > I'm going to close this, as I think G++ handles comment 1 correctly and both > EDG and Clang agree. > > I didn't check all your other examples in detail but I don't think they show > anything different: ADL doesn't find anything for built-in types such as int > or > char.
[Bug c++/53573] template type dependent name resolution broken
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53573 --- Comment #13 from Keean Schupke 2012-06-05 11:25:40 UTC --- (In reply to comment #9) >From ISO14882 14.6 - Name resolution [temp.res] -8- When looking for the declaration of a name used in a template definition, the usual lookup rules (basic.lookup.unqual, basic.lookup.koenig) are used for nondependent names. The lookup of names dependent on the template parameters is postponed until the actual template argument is known (temp.dep). [Example: #include using namespace std; template class Set { T* p; int cnt; public: Set(); Set(const Set&); void printall() { for (int i = 0; i, the actual declaration of operator<< needed to print p[i] cannot be known until it is known what type T is (temp.dep). ] -9- If a name does not depend on a template-parameter (as defined in temp.dep), a declaration (or set of declarations) for that name shall be in scope at the point where the name appears in the template definition; the name is bound to the declaration (or declarations) found at that point and this binding is not affected by declarations that are visible at the point of instantiation. [Example: void f(char); template void g(T t) { f(1); // f(char) f(T(1));// dependent f(t); // dependent dd++; // not dependent // error: declaration for dd not found } void f(int); double dd; void h() { g(2); // will cause one call of f(char) followed // by two calls of f(int) g('a'); // will cause three calls of f(char) } So it was like this in 1998, and it is the same in the latest working draft. --- end example] > (In reply to comment #2) > > The function called in the template definition is clearly dependent on the > > template parameter 'T' and therefore itsname should be resolved at the > > point of > > instantiation where 'g' is clearly defined and in scope (and is not local). > > The > > error message says: "no declarations were found by argument-dependent > > lookup at > > the point of instantiation" when 'g' should be found. > > Built-in types have no associated namespaces so ADL can not find 'g' via ADL. > A > declaration must be visible at the point of definition. > > The example in comment 1 is ill-formed. > > Paragraph 10 doesn't apply because the call is clearly dependent. > > N.B. N3242 is not the C++ standard and neither is "C++ Special Edition" which > is quite old now.
[Bug c++/53573] template type dependent name resolution broken
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53573 --- Comment #16 from Keean Schupke 2012-06-05 11:53:32 UTC --- (In reply to comment #14) Basic.lookup.argdep is not specific to templates, so why does the dependent lookup work outside of templates? int g(int x) { return x - 1; } double g(double x) { return x + 1.0L; } main() { int x(g(1.0L)); } why does ADL work here if [basic.lookup.argdep] means what you imply? > [temp.dep.res] says dependent name resolution considers declarations visible > at > the point of definition, and declarations from associated namespaces from the > instantiation context and the definition context. > > [basic.lookup.argdep]/2 says "If T is a fundamental type, its associated sets > of namespaces and classes are both empty."
[Bug c++/53573] template type dependent name resolution broken
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53573 --- Comment #19 from Keean Schupke 2012-06-05 12:55:06 UTC --- (In reply to comment #18) Sorry about that. It does indeed seem that the combination of [temp.dep.res] and [basic.lookup.argdep] imply this behaviour. I think my point was more about why it is different from usual lookup, any you are quite right this is not the place for that discussion. > (In reply to comment #16) > > why does ADL work here if [basic.lookup.argdep] means what you imply? > > That's not ADL, so I don't know what you're asking. > > Bugzilla is not the right place to learn C++, please take this to an > appropriate forum.
[Bug c++/53573] template type dependent name resolution broken
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53573 --- Comment #21 from Keean Schupke 2012-06-05 17:01:01 UTC --- (In reply to comment #20) Yes, once again sorry. Obviously not GCC's problem for implementing the standard correctly, but this causes problems producing elegant datatype generic code. For example if a concept is defined in a library (using Boost Concept Checking for example) and I want to make 'int' comply to that concept, I would have to declare the new int methods before including the library. This seems very odd in end user code. In this case there is nothing intuitively wrong with the way GCC was doing it - it was not difficult for the compiler authors to implement, and nor did it lead to incorrect or hard to understand code, in fact it worked very well for generic programming. Is there any chance this 'feature' of GCC could be kept as a g++ specific extension in 'gnu++11' mode, as I think the old behaviour is an improvement over that suggested in the standard, and GCC provides other extensions to standard behaviour where it is useful. > I'm under the impression that the bug reports using the word 'broken' are the > ones most likely broken, err invalid. Maybe just another manifestation of the > illusion of confidence, well known to the psychologjsts? (for a very nice > intro > see, eg, Chabris & Simons, 'The invisible gorilla', Ch 3)
[Bug c++/53573] template type dependent name resolution broken
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53573 --- Comment #23 from Keean Schupke 2012-06-27 06:48:28 UTC --- (In reply to comment #22) > (In reply to comment #21) > > Is there any chance this 'feature' of GCC could be kept as a g++ specific > > extension in 'gnu++11' mode, as I think the old behaviour is an improvement > > over that suggested in the standard, and GCC provides other extensions to > > standard behaviour where it is useful. > > I doubt it. The old behaviour was the source of several long-standing bug > reports. Now G++ implements the standard's required behaviour and agrees with > other leading compilers. GNU extensions usually allow new features by > supporting new syntax not by changing the meaning of valid code, it would not > be a pure extension. I have started a discussion on the C++ Standard discussion group about whether the code in the original example should work. So far the only responses have been to indicate that the code I posted is intended to work. Anyone wishing to discuss this further should post there: https://groups.google.com/a/isocpp.org/d/msg/std-discussion/OABibx-FK-o/srhSRlQduJAJ
[Bug c++/52065] New: template function of template class s;e
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52065 Bug #: 52065 Summary: template function of template class s;e Classification: Unclassified Product: gcc Version: 4.6.2 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ AssignedTo: unassig...@gcc.gnu.org ReportedBy: ke...@fry-it.com
[Bug c++/52064] New: template function of template class s;e
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52064 Bug #: 52064 Summary: template function of template class s;e Classification: Unclassified Product: gcc Version: 4.6.2 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ AssignedTo: unassig...@gcc.gnu.org ReportedBy: ke...@fry-it.com
[Bug c++/52065] Declaring template friend function of template class breaks template type inference.
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52065 Keean Schupke changed: What|Removed |Added CC||ke...@fry-it.com Summary|template function of|Declaring template friend |template class s;e |function of template class ||breaks template type ||inference. --- Comment #1 from Keean Schupke 2012-01-31 12:49:18 UTC --- /* g++ (Gentoo 4.6.2 p1.2, pie-0.5.0) 4.6.2 * * Linux Orac 3.0.0-gentoo #1 SMP Wed Oct 26 10:56:22 BST 2011 x86_64 Intel(R) Xeon(R) CPU X5570 @ 2.93GHz GenuineIntel GNU/Linux * * $ /var/tmp/portage/sys-devel/gcc-4.6.2/work/gcc-4.6.2/configure --prefix=/usr --bindir=/usr/x86_64-pc-linux-gnu/gcc-bin/4.6.2 --includedir=/usr/lib/gcc/x86_64-pc-linux-gnu/4.6.2/include --datadir=/usr/share/gcc-data/x86_64-pc-linux-gnu/4.6.2 --mandir=/usr/share/gcc-data/x86_64-pc-linux-gnu/4.6.2/man --infodir=/usr/share/gcc-data/x86_64-pc linux-gnu/4.6.2/info --with-gxx-include-dir=/usr/lib/gcc/x86_64-pc-linux-gnu/4.6.2/include/g++-v4 --host=x86_64-pc-linux-gnu --build=x86_64-pc-linux-gnu --disable-altivec --disable-fixed-point --without-ppl --without-cloog --enable-lto --enable-nls --without-included-gettext --with-system-zlib --disable-werror --enable-secureplt --enable-multilib --enable-libmudflap --disable-libssp --enable-libgomp --with-python-dir=/share/gcc-data/x86_64-pc-linux-gnu/4.6.2/python --enable-checking=release --enable-java-awt=gtk --disable-libquadmath --enable-languages=c,c++,java --enable-shared --enable-threads=posix --enable-__cxa_atexit --enable-clocale=gnu --enable-targets=all --with-bugurl=http://bugs.gentoo.org/ --with-pkgversion=Gentoo 4.6.2 p1.3, pie-0.5.0 * * g++ "thisfile.cpp" * * /tmp/.private/keean/ccl1iwQk.o: In function `main': * t.cpp:(.text+0x26): undefined reference to `void f(A, char)' * collect2: ld returned 1 exit status * * We have a function template which we want to allow access to the private * data of an object. The function template works fine just using the public * interface of the object, but adding the friend declaration seems to break * the type inference when the template function is called. * I can get this to compile by changing the friend definition to: * * template friend void f(A, T2); * * However this does not mean the same thing as nothing is constraining * TT == T so this would in fact allow private access to instances of 'f' * of _all_ types of A<*> not just the ones where the type first type parameter * is the same type as the type parameter of the template object. */ template struct A; template void f(A a, T2 b) { a.t = b; } template struct A { A(T a) {t = a;} template friend void f(A, T2); //template friend void f(A, T2); private: T t; }; int main() { A a(1); f(a, 2.1); }