Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Tools to generate higher-quality error messages for template-based code?

Concepts, that would render these tools unnecessary, are not part of C++11.

  • STLFilt would have been one option but it is no longer maintained.

  • Clang claims to give expressive diagnostics although important C++11 features are not available yet.

  • colorgcc seems to be abandoned since 1999.

What production quality tools are available to decipher error messages stemming from template-based code? Eclipse-CDT support would be nice too. :)

If I give up on C++11, what options do I have for C++98?


Related questions:

  • Deciphering C++ template error messages
  • Improving g++ output
like image 459
Ali Avatar asked Jan 08 '12 17:01

Ali


2 Answers

Let's have a stab at an answer (I marked this community wiki so we get a good response together)...

I'm working since a long time with templates and error messages have generally improved in some way or another:

  • Writing a stack of errors creates a lot more text but also typically includes the level the user is looking at and this generally includes a hint at what the actual problem is. Given that the compiler only sees a translation unit tossed at it, there isn't a lot which can be done determining which error in the stack is the one most suitable for the user.
  • Using concept checkers, i.e. classes or functions which exercise all the required members of template arguments and possibly generating errors messages using static_assert() give the template author a way to tell users about assumptions which apparently don't hold.
  • Telling the user about types he writes rather than expanding all typedefs as the compiler like to see at the lowest level also helps. clang is rather good at this and actually gives you error messages e.g. talking about std::string rather than expanding things type to whatever it ends up to be.

A combination of the technique actually causes e.g. clang to create quite decent error message (even if it doesn't implement C++2011, yet; however, no compiler does and as far as I can tell gcc and clang are leading the pack). I know other compiler developers actively work on improving the template error messages as lots of programmers have discovered that templates actually are a huge leap forward even though the error messages are something which takes a bit of getting used to.

One problem tools like stlfilt face is that C++ compilers and libraries are under active development. This results in error messages shifting all the time, causing the tool to receive different outputs. While it is good that compiler writers work on improving error messages, it certainly makes life harder for people who try to work from the error messages they got. There is another side to this as well: once a certain error pattern is detected to be common and is picked up e.g. by stlfilt (well, it isn't actively maintained as far as I know) compiler writers are probably keen to report the errors following these patterns directly, possibly also providing additional information available to the compiler but not emitted before. Put differently, I would expect that compiler writers are quite receptive to reports from users describing common error situations and how they are best reported. The compiler writers may not encounter the errors themselves because the code they are working on is actually C (e.g. gcc is implemented in C) or because they are so used to certain template techniques that they avoid certain errors (e.g. omission of typename for dependent types).

Finally, to address the question about concrete tools: the main "tool" I'm using when I get kind of stuck with a compiler complaining about some template instantiation is to use different compilers! Although it isn't always the case but often one compiler reports an entirely incomprehensible error messages which only makes sense after seeing the fairly concise report from another compiler (in case you are interested, I regularly use recent version of gcc, clang, and EDG for this). I'm not aware of a readily packaged too like stlfilt, however.

like image 66
Dietmar Kühl Avatar answered Oct 21 '22 17:10

Dietmar Kühl


I know this may not be as helpful as you wanted, but I've found the best tool against template error messages is knowledge.

A good understanding of the STL and how to use it will help you avoid lots of errors in the first place. Secondly, often error messages refer to functions in the STL source - if you have a rough idea how the STL is implemented, this can be extremely helpful in deciphering what the error message is going on about. Finally, compiler makers are aware of this issue and are gradually improving error message output, so you would do well to stick to the latest version of your compiler.

Here's a good example of an obscure template error:

std::vector<std::unique_ptr<int>> foo; std::vector<std::unique_ptr<int>> bar = foo; 

unique_ptr is not copyable, it can only be moved. So trying to assign a vector of unique_ptr to another vector will mean somewhere in the vector source code will try to copy a unique pointer. Therefore the error will originate from code which is not yours and throw a fairly opaque error message as a result. The ideal error message would be

main.cpp(20): cannot construct 'bar' from 'foo': foo's template type is non-copyable

Instead, VS2010 gives the following error:

1>C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xmemory(48): error C2248: 'std::unique_ptr<_Ty>::unique_ptr' : cannot access private member declared in class 'std::unique_ptr<_Ty>' 1>          with 1>          [ 1>              _Ty=int 1>          ] 1>          C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\memory(2347) : see declaration of 'std::unique_ptr<_Ty>::unique_ptr' 1>          with 1>          [ 1>              _Ty=int 1>          ] 1>          C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xmemory(197) : see reference to function template instantiation 'void std::_Construct<std::unique_ptr<_Ty>,const std::unique_ptr<_Ty>&>(_Ty1 *,_Ty2)' being compiled 1>          with 1>          [ 1>              _Ty=int, 1>              _Ty1=std::unique_ptr<int>, 1>              _Ty2=const std::unique_ptr<int> & 1>          ] 1>          C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xmemory(196) : while compiling class template member function 'void std::allocator<_Ty>::construct(std::unique_ptr<int> *,const _Ty &)' 1>          with 1>          [ 1>              _Ty=std::unique_ptr<int> 1>          ] 1>          C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\vector(421) : see reference to class template instantiation 'std::allocator<_Ty>' being compiled 1>          with 1>          [ 1>              _Ty=std::unique_ptr<int> 1>          ] 1>          C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\vector(481) : see reference to class template instantiation 'std::_Vector_val<_Ty,_Alloc>' being compiled 1>          with 1>          [ 1>              _Ty=std::unique_ptr<int>, 1>              _Alloc=std::allocator<std::unique_ptr<int>> 1>          ] 1>         main.cpp(19) : see reference to class template instantiation 'std::vector<_Ty>' being compiled 1>          with 1>          [ 1>              _Ty=std::unique_ptr<int> 1>          ] 

Sifting through this there are clues. The first section references a private member access of std::unique_ptr<int>. The second section, if you click through to the source line, points at the copy constructor of unique_ptr, which is declared beneath a private: specifier. So now we know we tried to copy a unique_ptr which is not allowed. Sections 3, 4 and 5 just point to boilerplate code - it's just noise. Section 6 says "see reference to class template instantiation 'std::_Vector_val<_Ty,_Alloc>' being compiled". In other words, this error happened in vector's template code. The last section is most interesting: it directly points at the line declaring foo in your own source code - it's figured out where in your own source code the error originated from!

So adding up the clues:

  • It originates in foo,
  • It originates in vector code,
  • It tries to copy a unique_ptr which is not allowed.
  • Conclusion: the vector tried to copy one of its elements, which is not allowed. Review code for foo and check for anything causing a copy.

Since the compiler only pointed at foo's declaration, if the assignment is far away in the source code some hunting will be involved. This obviously is not ideal, but I think this approach ultimately gives you more chance of fixing mistakes in general. You'll start to recognise that kind of error dump means "you copied a unique_ptr". Again, I'm not defending it, it definitely needs improving - but I think these days there's just enough information in the output that combined with a good knowledge of the STL allows you to fix the problem.

like image 41
AshleysBrain Avatar answered Oct 21 '22 18:10

AshleysBrain