compiler stack overflow on template code
Asked Answered
B

3

7

While working on my own type erasure iterator, I ran into an issue where the compiler (MSVC10) crashed with a stack overflow on this code:

struct base {};  //In actual code, this is a template struct that holds data
template<class category, class valuetype>  
    struct any;  //In actual code, this is abstract base struct
template<class basetype, class category, class valuetype> 
    struct from; //In actual code, this is function definitions of any

template<class valuetype>
struct any<void,valuetype>
{ void a() {} };
template<class category, class valuetype>  
struct any
    : public any<void,valuetype> //commenting this line makes it compile
{ void b() {} };        

template<class basetype, class valuetype>
struct from<basetype,void,valuetype>
    : public base  //commenting out _either_ of these makes it compile
    , public any<void,valuetype>
{ void c() {} };

int main() {
    from<int, void, char> a;
    a.a();
    a.c();
    any<int, char> b;
    b.a();
    b.b();
    return 0;
}

Obviously, I've removed everything I can where the bug remains. (Origional code was 780+ lines) Removing any remaining template parameters causes the code to compile.

The full error message is:

main.cpp(23): fatal error C1063: compiler limit : compiler stack overflow
    main.cpp(20) : see reference to class template instantiation 'from<basetype,void,valuetype>' being compiled

IDEOne compiles it fine. I've heard that MSVC implemented two-phase lookup wrong, which seems relevant, but doesn't explain why it compiles when I remove the line that makes from inherit from base. Can anyone teach me why MSVC10 won't compile this? What did I do that I should be avoiding?

Bone answered 13/12, 2011 at 20:53 Comment(14)
For what it is worth, GCC 4.6 compiles your sample code without trouble (on Linux/Debian/Sid/AMD64). Perhaps you could switch to GCC (e.g. some MinGW or Cygwin variant...) ?Amritsar
I actually did a fair amount of debugging via IDEOne, but my command-line-fu and linux are weak, so Cygwin is intimidating. I'm beginning to toy with it though.Bone
You have a template class which inherits from itself? Or am I reading this wrong?Learned
Be sure to get GCC 4.6 since it is progressing a lot for latest C++ standard compliance...Amritsar
@AJG85: iterator_from_any<category> inherits from the iterator_from_any<void> specialization, which is legal C++, but might be what's tripping up MSVC10.Bone
@MooingDuck: That certainly trips me up. Didn't know you can inherit from a partial specialization of yourself but technically I guess that's a new type? Have you tried playing with compiler settings on MSVC10?Learned
@AJG85: Each template instantiation is it's own type, so yes, they can inherit from each other, as long as depth is less than 1024 (in my case it's 2, so definitely less). I haven't found any settings that look likely. Any suggestions?Bone
@MooingDuck: Not really. I just fiddled a bit with disabling extensions and optimizations but same crash no matter what I tried. I had a hunch that because the specialization was based off a forward declaration before the definition is encountered that it might get optimized out before the instantiation making it think the base class was itself when cl.exe runs.Learned
Please consider reporting this as a bug at Microsoft Connect and report back here with a link to it. If you don't want to report the issue, let me know and I am happy to report it.Vale
Huh, sorry for the question, but WTF is this? O.oHooknosed
bug report at connect.microsoft.com/VisualStudio/feedback/details/714003Bone
@BlackBear: an implementation of any_iterator using type erasure. Which part is confusing you?Bone
@MooingDuck: pretty much everything since I haven't got any experience in C++ ;)Hooknosed
@BlackBear: ah, this is... a rather technical question. any is a nested abstract interface, and from is a nested implementation.Bone
V
1

As a workaround, consider introducing an additional class between the unspecialized any and the specialization with category = void:

template <class valuetype>
class detail_void_any
    : public any<void, valuetype>
{
};


template<class category, class valuetype>
class any
    : public detail_void_any<valuetype>
{
};

The following complete program should compile without error:

class base {};      // Data Holder (in reality it's templated, so required)
template<class category, class valuetype>  
        class any;  // Virtual Function Interface
template<class basetype, class category, class valuetype> 
        class from; // Virtual Function Implementation

template<class valuetype>
class any<void,valuetype>
{};


template <class valuetype>
class detail_void_any
    : public any<void, valuetype>
{
};

template<class category, class valuetype>
class any
    : public detail_void_any<valuetype>
{
};

template<class basetype, class valuetype>
class from<basetype,void,valuetype>
        : public base  //commenting out _either_ of these makes it compile
        , public any<void,valuetype>
{}; //this is line 23, where the compiler crashes

int main() {return 0;}
Vale answered 14/12, 2011 at 17:43 Comment(0)
L
1

Well I give up but I did manage to generate a warning:

template <typename T1, typename T2>
class Any; // forward

template <typename T2>
class Any<void, T2> // partial spec of forward
{};

template <typename T1, typename T2>
class Any: // template definition
    public Any<void, T2> // inherit from partial spec
{};

template <typename T1, typename T2>
class From :
    public Any<int, T2>, // inherit definition
    public Any<void, T2> // inherit definition or partial spec?
    // with spec first we get fatal error C1063: compiler limit : compiler stack overflow (CRASH!)
    // with definition first we get warning C4584: 'From<T1,T2>' : base-class 'Any<void,T2>' is already a base-class of 'Any<int,T2>'
{};

int main()
{
    return 0;
}
Learned answered 13/12, 2011 at 22:40 Comment(4)
Note that my code has three template classes, Test only inherits from Whatever<void> and an unrelated class. Test does not inherit from Whatever<int>. I'll try reversing the inheritance order though, and see if that fixes anything.Bone
Reversing the inheritance of Whatever<void> and the unrelated type does not fix the issue. I can't see any real difference between your code and mine...Bone
I've renamed the classes and rearranged them to make it slightly more obvious why each of the classes is required and how the parts work.Bone
Yeah this is maybe only a slightly slimmed down reproduction as I couldn't find a syntax that worked in VS2010 and I'm on SP1. The catch seems to be if the non-specialized template is not the first base class it crashes. You might want to send this to Microsoft if you haven't already I'd be curious to see what they have to say about it.Learned
V
1

As a workaround, consider introducing an additional class between the unspecialized any and the specialization with category = void:

template <class valuetype>
class detail_void_any
    : public any<void, valuetype>
{
};


template<class category, class valuetype>
class any
    : public detail_void_any<valuetype>
{
};

The following complete program should compile without error:

class base {};      // Data Holder (in reality it's templated, so required)
template<class category, class valuetype>  
        class any;  // Virtual Function Interface
template<class basetype, class category, class valuetype> 
        class from; // Virtual Function Implementation

template<class valuetype>
class any<void,valuetype>
{};


template <class valuetype>
class detail_void_any
    : public any<void, valuetype>
{
};

template<class category, class valuetype>
class any
    : public detail_void_any<valuetype>
{
};

template<class basetype, class valuetype>
class from<basetype,void,valuetype>
        : public base  //commenting out _either_ of these makes it compile
        , public any<void,valuetype>
{}; //this is line 23, where the compiler crashes

int main() {return 0;}
Vale answered 14/12, 2011 at 17:43 Comment(0)
V
1

Simplest workaround: Replace:

template<class category, class valuetype>
class any : public any<void, valuetype>
{
};

with:

template<class valuetype, class category>
class any : public any<void, valuetype>
{
};
Villegas answered 14/12, 2011 at 18:19 Comment(3)
@Xeo: actually... It seems to work... I added member functions to verify. WTF? Good find...Bone
@Mooing: It shouldn't do that, since you'd need to switch the template parameters for the void case too.Melosa
@Xeo: ah right, my little test didn't verify that it was category that was void.Bone

© 2022 - 2024 — McMap. All rights reserved.