I may well just be missing some silly option in the boatload of options available in MSVC 2022 that changed in terms of their defaults (please tell me if so), but I can't seem to get a compile-time stack trace when we encounter errors in the middle of function or class templates.
Basic example in MSVC 2022:
template <class T>
void foo()
{
static_assert(false);
}
int main()
{
foo<int>();
}
In MSVC 2022 with default settings, all I get is a "static assert failed" kind of message. It doesn't tell me who called foo. Whereas in MSVC 2019, I got a full compile-time stack trace letting me know that calling foo failed down to the precise line that called foo.
I'm really missing that extra info from 2019. But I have a sneaking suspicion that there's some option in Tools->Options I'm not aware about to enable this output behavior again.
Picture:
Anyone else encountering this issue after upgrading to 2022 from 2019 and/or have a fix for it?
MSVC 2019 as a comparison where I got error messages in templates that are actually usable to help me figure out where/how they occurred!
Also, I only used static_assert to produce a bare minimum and reproducible result. I'm lacking this stack trace on every kind of error that occurs inside a function or class template.
In response to the automated Q for the site:
I tried going through all the options I could find and searching Google along with this site for answers. In fairness, I'm an old and dumb guy now so I might have overlooked something obvious. I really think that has to be the most obvious answer since MSVC 2022 has been out for a long time now and I figure other people would have complained left and right in ways I could easily find if this wasn't a behavior we can revert. I'm really hoping I'm overlooking something because that would totally suck if we can no longer see the compile-time call stack for errors in class and function templates (that's actually omitting crucial info in many cases, since it may not be an error with the template/callee but an error in the way the caller calls the callee).
Stack Trace?
My bad if I used the wrong terminology for this. I got a comment pointing this out. I am thinking about something that is like tracing the call stack (not calling, but evaluating calls in a nested fashion at compile time as we parse, generate AST, generate IR, optimize IR, etc.). That could be a second question as a bonus if I'm using "compile-time stack trace" incorrectly! What's the proper term? English is not my first language as a half-excuse but I'm probably just really dumb!
Update in Response to HolyBlackCat
I just made a project with the default settings using your code and got the type of errors I expect and wanted from MSVC 2019! A sample of the errors I get which match yours:
1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.34.31933\include\memory(3256,5): message : see declaration of 'std::unique_ptr<int,std::default_delete<int>>::unique_ptr'
1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.34.31933\include\memory(3256,5): message : 'std::unique_ptr<int,std::default_delete<int>>::unique_ptr(const std::unique_ptr<int,std::default_delete<int>> &)': function was explicitly deleted
1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.34.31933\include\vector(852,1): message : see reference to function template instantiation 'void std::_Default_allocator_traits<_Alloc>::construct<_Ty,const _Ty&>(_Alloc &,_Objty *const ,const _Ty &)' being compiled
1> with
1> [
1> _Alloc=std::allocator<std::unique_ptr<int,std::default_delete<int>>>,
1> _Ty=std::unique_ptr<int,std::default_delete<int>>,
1> _Objty=std::unique_ptr<int,std::default_delete<int>>
1> ]
1>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.34.31933\include\vector(863,36): message : see reference to function template instantiation 'void std::_Default_allocator_traits<_Alloc>::construct<_Ty,const _Ty&>(_Alloc &,_Objty *const ,const _Ty &)' being compiled
1> with
1> [
1> _Alloc=std::allocator<std::unique_ptr<int,std::default_delete<int>>>,
1> _Ty=std::unique_ptr<int,std::default_delete<int>>,
1> _Objty=std::unique_ptr<int,std::default_delete<int>>
1> ]
So that's great and wonderful! I at least like this part of MSVC 2022. But I could swear that I was getting errors in function and class templates in our project that didn't show this for whatever reason. I tried to use static_assert(false) as an MVE. But it seems like some cases show us hierarchy of callers and not just the error in the callee and some cases don't... although I still think seeing that even for static_assert fails is so useful!
Had a chance to test my theory from my comments. The issue is with trying to be standards compliant.
You likely have /permissive- flag set, to be standards compliant (default when C++20 is used). This enables two phase name lookups for templates. Under the non-standard parsing which Microsoft did before:
It parses only the template declaration, the class head, and the base class list. The template body is captured as a token stream. No function bodies, initializers, default arguments, or noexcept arguments are parsed. The class template is pseudo-instantiated on a tentative type to validate that the declarations in the class template are correct.
...
When it parses a function template, the compiler parses only the function signature. The function body is never parsed. Instead, it's captured as a token stream.
In this, non-standard mode, it ignores the static_assert( false ), until it is instantiated from main, in which case you get the information about who's instantiating it.
In the standards compliant mode, it does parse the body, and sees the static_assert( false ) and fails immediately, before any instantiation is done.
If you want the old behaviour, you can turn off the standards conformance by specifying /permissive (though I would not recommend this). You can disabled just the two-phase name lookup (again, not really recommended) by specifying /Zc:twoPhase-
See more here: https://learn.microsoft.com/en-us/cpp/build/reference/zc-twophase?view=msvc-170
Also, example (side by side) with two phase on and off here: https://godbolt.org/z/MPEWGsYTx (godbolt gives less details in its output than MS, but does show its instantiation)
Note: The compile still gives information on who's instantiating if the issue is with the caller, not the callee.
Funny aside: when MS first did this, they broke their own code in the process, and caused a whole lot of programs to stop compiling because they were using static_assert( false ) in their Unit test framework ... I guess they forgot to use their own unit testing before pushing it out :P
Related
I am new to C++ programming. I am trying to compile another person's program, and the software reported a bug that I don't know how to solve (the software I use is Visual Studio 2019).
The line of code with bug is:
swap(allBeamPoints, unordered_map<int, vector<LidarPoint>>());
The definition for variable allBeamPoints is:
unordered_map<int, vector<LidarPoint>>allBeamPoints
The error information is:
Error C2665 'std::swap': none of the 2 overloads could convert all the argument types
and
Error (active) E0304 no instance of overloaded function "swap" matches the argument list
However, if I type the following codes, no bug will be reported:
unordered_map<int, vector<LidarPoint>> allBeamPoints_new;
swap(allBeamPoints, allBeamPoints_new);
Does anyone know what the problem is? Did I fail to link some of the required libraries? How should I check those libraries?
The older MSVC compilers allowed the binding of an anonymous temporary to a non-const reference function parameter. That's not standard C++.
So
swap(allBeamPoints, unordered_map<int, vector<LidarPoint>>());
which had the effect of clearing allBeamPoints was reasonably idiomatic in code that only targeted Microsoft platforms.
It's wrong and not portable as you now observe. Use
allBeamPoints.clear();
instead to clear the map. Your second snippet compiles since allBeamPoints_new is not an anonymous temporary.
I'm using visual studio 2017 and I noticed that I don't get syntax error warnings when using template, for example:
and when I remove the template I get this:
and this:
Is it possible to fix this?
code(not image):
template<int a>
void noErrors()
{
sleiudbg;sg ojrp jabp srpghs //some gibberish
}
template<int b>
void noErrors(string s)
{
int p = s.Size();
}
Oh please, must we post code only as images? Please fix that, it means I cannot experiment with your code.
But the answer to your question is that the incremental syntax checker built into the IDE is of limited intelligence, especially where templates are concerned (where detecting and reporting compiler errors in general is a complex business) and as a result a great deal of stuff which is not going to compile slips through.
The compiler, on the other hand, will throw this out straightaway, and also report errors resulting from an invalid instantiation of a template in a moderately helpful way (although such error messages are never the easiest things to read).
And can you change any of this? Sorry, no, (unless you can persuade Microsoft to beef-up their IDE).
where error checking is a complex business - more here:
What does a compiler check for uninstantiated template code?
I have some code which compiles fine under Linux, but I am trying to port it to Windows. I have used the Boost 1.50 precompiled binaries from Boost Pro, but when I compile my code I get this cryptic error:
error C2664: 'boost::_bi::bind_t<R,F,L>::bind_t(const boost::_bi::bind_t<R,F,L> &)' :
cannot convert parameter 1 from 'boost::_bi::bind_t<R,F,L>'
to 'const boost::_bi::bind_t<R,F,L> &'
C:\Program Files (x86)\boost\boost_1_50\boost\bind\bind_cc.hpp [line] 50
The error is most unhelpful because it shows up deep in the Boost header files, with no indication of where in my code the problem is. Nevertheless by commenting out various blocks of code I have narrowed it down to this as the cause:
void test(int a)
throw (int) // removing this line makes it compile
{
return;
}
...
boost::function<void(int)> fn = boost::bind<void>(test, _1);
It works if I remove the throw specifier in the function definition. It doesn't matter what I throw, whether it's a class or just an int. Am I doing something wrong, or can't you bind to functions that throw exceptions in Visual C++? The Boost Bind docs don't seem to suggest any issues with this, and GCC doesn't have a problem with it either way.
[Side note: The code above is not my actual code, but when compiled it exhibits the same problem. Please avoid comments about throwing ints being bad and the like, as this is only supposed to be a trivial example in case anyone wishes to reproduce the problem.]
I don't know why your code fails on VC++. However, in general exception specifications are best avoided because they can introduce very subtle effects. See this excellent column A Pragmatic Look at Exception Specifications by Herb Sutter:
So here’s what seems to be the best advice we as a community have
learned as of today:
Moral #1: Never write an exception specification.
Moral #2: Except possibly an empty one, but if I were you I’d avoid
even that.
I have a piece of code that pretty much reduces down to:
template<class T> struct MyStruct; // No definition by default
template<class T> struct MyStruct<T *> { ... }; // Specialization for pointers
Now somewhere in my code, I'm getting an instantiation of MyStruct<T> that happens to be undefined (no C++0x/011, no Boost... nothing fancy, just plain C++03):
error C2027: use of undefined type 'MyStruct<T>'
The trouble is, I have no idea where this is being caused, because the code that's doing the instantiation is itself a template, and called from numerous places, with different arguments.
Is there a way to somehow figure out what T is at compile-time, so I can understand the error messages better?
(Sorry, I forgot to mention: Visual Studio 2008.)
I believe you're using MSVC++, if so, then see the output window, it might have more info printed, especially the line number along with the filename. Once you know the file and line number, you can start from there.
Output window usually prints everything, like how and with what template argument(s), a template is instantiated. Everything step by step. Those messages are very useful when debugging.
As you found yourself, enabling /WL prints more detail messages in the output window.
I know you said no C++11, but you may want to consider, since C++03 code is backwards compatible in all C++11 compliant compilers, to use the static_assert feature of C++11 to debug your code ... if you must do the final compile with a C++03 compiler, then you can always create a #define and use the #ifdef and #endif pre-processor macros to make sure that the static_assert feature does not cause problems in earlier compilers that do not support C++11 features.
See the MSDN docs here for more info.
For example, say for some reason I had a piece of code that looked like this:
mutable std::vector<std::vector<std::vector<std::vector<
std::vector<MyNamespace::MyType> > > > > myFreakingLongVectorThing;
and I am getting a warning that looks like this:
C:\Program Files (x86)\Microsoft Visual Studio 8\VC\include\xstring(1665) : warning
C4503: 'std::vector<_Ty>::operator []' : decorated name length exceeded, name was truncated
with
[
_Ty=std::vector<std::vector<std::vector<std::vector<std::vector<MyNamespace::MyType>>>>>
]
is there any way I could rewrite that freaking long vector thing to not get that warning? I still want the data structure to be the same, but not get that warning. I don't want to disable the warning. Possible?
Note: This is Visual Studio 2005
....if you're really curious about why I'm working with such a hideous data structure, it's caused by auto-generated code.
If you don't want to see the warning you either have to disable it or use a newer compiler.
The warning is about debug information being limited to 255 characters for the type name. As long as these 255 characters are not identical for two different types, you are ok. And if they are identical, you cannot do much about it anyway!
Just turn it off until you can upgrade the compiler!
This isn't all that different from the error I used to get in Visual C++ 6 anytime I did just about anything with STL maps. You simply need to bite the bullet and tell the compiler to shut up about that warning. It's got a fundamental internal limit on how long a type name can be. As it is, it's a pretty useless warning, just complaining about the compiler/debugger's internal name limit.
#pragma warning(disable : 4503)
And if you're thinking at all about porting to another compiler, just wrap it in a #ifdef for Visaul C++:
#ifdef MSVC
#pragma warning(disable : 4503)
#endif