
On Tue, Apr 6, 2010 at 7:53 PM, Peter Dimov <pdimov@pdimov.com> wrote:
Eric Niebler wrote:
Actually, I may have been too hasty. I notice the same behavior on recent gcc builds. That is, the following program causes both vc10 and gcc in std=c++0x mode to run out of heap space.
template<class T> struct S;
template<class X, class Y> struct pair {};
template<class T> S<T> wrap(T) { return 0; }
template<class T> struct S { S(int = 0) {}
// The following use of decltype causes the compiler to blow up: decltype(wrap(pair<T,T>())) foo() { return wrap(pair<T,T>()); }
This is a CWG question. I don't think that the compilers need to instantiate the definition of S<pair<int,int>> from within the decltype, but it appears that they do, and the standard may well require them to. The other unevaluated context, sizeof, would instantiate because it needs the size, and if decltype shares the same code, it will too.
I just took a closer look at this. I ran gcc on Eric's example for 30 minutes without ICE, but it never halted. I got an error "invalid use of incomplete type" on a more minimal example. template<class T> struct S; template<class T> S<T> wrap(T) { return 0; } template<class T> struct S { typedef decltype(wrap(T())) type; // error }; int main() { S<int> s; } I believe the error is in compliance with the draft standard. N3092 7.1.6.2.4 states: "The type denoted by decltype(e) is defined as follows: ... if e is a function call (5.2.2) or an invocation of an overloaded operator (parentheses around e are ignored), decltype(e) is the return type of the statically chosen function;" 5.2.2.3 states: "The type of the function call expression is the return type of the statically chosen function (i.e., ignoring the virtual keyword), even if the type of the function actually called is different. This type shall be a complete object type, a reference type or the type void." So, it seems the draft requires compilers to reject code taking decltype of an incomplete type. Daniel Walker