Bug 40315

Summary: template instantiation fails when using const typename
Product: gcc Reporter: doriankrause
Component: c++Assignee: Not yet assigned to anyone <unassigned>
Severity: normal CC: bangerth, fang, gcc-bugs, jason
Priority: P3    
Version: 4.4.0   
Target Milestone: ---   
Host: Target:
Build: Known to work:
Known to fail: Last reconfirmed: 2009-11-08 04:33:37
Attachments: patch

Description doriankrause 2009-05-31 13:15:04 UTC
Consider the program:


template<int D>
class Foo
	typedef double	double3[3];

template<int D>
void doSomething(const typename Foo<D>::double3)

void doSomething<2>(const Foo<2>::double3);

void doSomething<3>(const Foo<3>::double3);


On Mac os X 10.5 it fails with gcc-4.4.0 (and also with the default gcc 4.0.1) with the error message

> /usr/local/gcc-4.4.0/bin/g++ -v test.cc
Using built-in specs.
Target: i686-apple-darwin9
Configured with: ./configure --prefix=/usr/local/gcc-4.4.0 --disable-checking -enable-werror --enable-languages=c,c++,fortran --build=i686-apple-darwin9 --with-tune=generic --host=i686-apple-darwin9 --target=i686-apple-darwin9
Thread model: posix
gcc version 4.4.0 (GCC) 
COLLECT_GCC_OPTIONS='-mmacosx-version-min=10.5.6' '-v' '-shared-libgcc' '-mtune=generic'
 /usr/local/gcc-4.4.0/libexec/gcc/i686-apple-darwin9/4.4.0/cc1plus -quiet -v -D__DYNAMIC__ test.cc -fPIC -quiet -dumpbase test.cc -mmacosx-version-min=10.5.6 -mtune=generic -auxbase test -version -o /var/folders/jq/jqHHJIlXEbOleEkgf132gE+++TI/-Tmp-//cctUrpft.s
ignoring nonexistent directory "/usr/local/gcc-4.4.0/lib/gcc/i686-apple-darwin9/4.4.0/../../../../i686-apple-darwin9/include"
#include "..." search starts here:
#include <...> search starts here:
End of search list.
GNU C++ (GCC) version 4.4.0 (i686-apple-darwin9)
	compiled by GNU C version 4.4.0, GMP version 4.2.1, MPFR version 2.3.0.
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: 4703a3934dc941165107f7c66932f1e1
test.cc:15: error: template-id 'doSomething<2>' for 'void doSomething(const double*)' does not match any template declaration
test.cc:18: error: template-id 'doSomething<3>' for 'void doSomething(const double*)' does not match any template declaration

Removing the const clarifier gives no errors.
Comment 1 Wolfgang Bangerth 2009-08-25 15:39:01 UTC
Hm, interesting. I would have thought as well that the code should compile.
On the other hand, icc also produces the same error message, so I am now
officially confused...
Comment 2 Jonathan Wakely 2009-08-26 14:43:09 UTC
IIUC, the top-level const qualifier on "const typename Foo<D>::double3" in the primary template applies to the type, which is not known during phase 1

At instantiation time, double3 is known to be an array type, so decays to a pointer, and the parameter type becomes "const double*" _not_ "double* const"

So the explicit instantiation creates a type which does not match the primary template, so it cannot be a specialisation of it.
Comment 3 Jonathan Wakely 2009-08-26 14:51:54 UTC
(In reply to comment #2)
> IIUC, the top-level const qualifier on "const typename Foo<D>::double3" in the
> primary template applies to the type, which is not known during phase 1

i.e. it's equivalent to "typename Foo<D>::double3 const" which is equivalent to simply "typename Foo<D>::double3) because top-level cv-qualifiers are removed from function parameters.
but when double3 is known to be an array type, which is replaced by a pointer in a parameter list, then the declaration's meaning changes.


typedef double  double3[3];
void f(const double3);
typedef void (*ptr)(const double*);
ptr p = f;

This demonstrates that the declaration of 'f' is equivalent to:

void f(const double*);


void f(double* const);

According to [dcl.fct] array parameters are replaced with pointers before top-level cv-qualifiers are deleted.

I think GCC is correct, the template specializations are invalid.
Comment 4 doriankrause 2009-08-26 19:26:37 UTC
Thanks Jonathan for your explanation. Now I can understand the reason behind this... (though I'm not really happy with the fact that you need to understand sort of internals to see why code doesn't compile). 

Do I need to mark the bug-report as invalid, or how does it work?

Comment 5 Jason Merrill 2009-11-08 04:37:43 UTC
I think this is a bug; we shouldn't be dropping the const at template parsing time.
Comment 6 Jason Merrill 2009-11-08 23:06:11 UTC
Actually, I'm not so sure:

template<class T>
struct A
  typedef A arr[3];

template<class T>
void f(const typename A<T>::arr) { }

template void f<int>(const A<int>::arr); // #1

template <class T>
struct B
  void g(T);

template <class T>
void B<T>::g(const T) { } // #2 

it seems to me that either #1 is well-formed, or #2 is, though it might make sense to recompute the function type from the parameter type...in any case, I'm opening a DR about this.
Comment 7 Jason Merrill 2009-11-08 23:32:45 UTC
Created attachment 18996 [details]

Here's a patch that fixes the testcase and passes regression testing, but I don't think it's the right way to go.
Comment 8 Paolo Carlini 2009-11-08 23:41:29 UTC
Jason, the extra const in the library code is definitely unintended, I'm going to remove it anyway.
Comment 9 Jason Merrill 2010-02-19 21:21:55 UTC
Suspending until the committee can rule on this, but I expect the result to be that the testcase is ill-formed.
Comment 10 Jonathan Wakely 2011-05-04 17:38:37 UTC
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#1001 is NAD so I think we can close this bug as INVALID
Comment 11 Jason Merrill 2011-05-04 18:14:36 UTC