We are working hard on improving the diagnostics experience in MSVC and Visual Studio. We began this work in Visual Studio 2022 version 17.3 and while not everything is ready yet, we would like to share the early progress.
Motivation & Principles
New C++ features like concepts and ranges present the opportunity for more expressive code and better-defined APIs. However, to make the most of them, better diagnostics are required from tooling so that constraint failures can be pinpointed and resolved.
We are aware that there is a lot of room for improvement, as noted by many of you on Developer Community, and we are now actively investing in this area.
Our developer advocate Sy Brand submitted a paper to WG21 which discusses the key principles of compiler diagnostics, and how the state of the art in C++ compilers can be improved. We are using this document as guidance in the design of our work.
As a first step, we are working on the compiler to make sure it gathers all the available information and can output it in a tool-friendly way for human consumption later. We are also adding new diagnostic visualization capabilities to Visual Studio to make it easier to navigate and understand large errors.
- The last message for template instantiation contexts now displays the text column which the error occurred at.
- The compiler now lists all candidates for a function call and explains why each candidate fails.
- The error message for unsatisfied associated constraints is expanded to detail which underlying constraints were not satisfied.
Compiler output in 17.2
example.cpp(15,2): error C2664: 'void functor::operator ()(long *)': cannot convert argument 1 from 'T' to 'long *' with [ T=double ] f(t); ^ example.cpp(8,7): note: see declaration of 'functor::operator ()' void operator()(long *); ^ example.cpp(20): note: see reference to function template instantiation 'void test
Compiler output in 17.4
example.cpp(15,2): error C2665: 'functor::operator ()': no overloaded function could convert all the argument types f(t); ^ example.cpp(7,7): note: could be 'void functor::operator ()(int *)' void operator()(int *); ^ example.cpp(15,2): note: 'void functor::operator ()(int *)': cannot convert argument 1 from 'T' to 'int *' with [ T=double ] f(t); ^ example.cpp(8,7): note: or 'void functor::operator ()(long *)' void operator()(long *); ^ example.cpp(15,2): note: 'void functor::operator ()(long *)': cannot convert argument 1 from 'T' to 'long *' with [ T=double ] f(t); ^ example.cpp(6,7): note: or 'void functor::operator ()(T)' void operator()(T); ^ example.cpp(15,2): note: the associated constraints are not satisfied f(t); ^ example.cpp(5,12): note: the concept 'std::integral
IDE experience in 17.4 (in-box viewer)
IDE experience in 17.4 (SARIF viewer extension)
The compiler changes often generate more text, and it sometimes makes understanding them harder. We are experimenting with a new compiler option to output the diagnostics into the Static Analysis Results Interchange Format (SARIF). The output will be loaded by Visual Studio to visualize the hierarchy of the messages so that it is easier to navigate.
Currently, clicking an error which is associated with SARIF output in the Visual Studio error list will bring up a pop up with collapsible diagnostic information. We are also working on a SARIF Viewer extension to provide a richer experience.
Here are the three areas the compiler focuses on right now.
General infrastructure (source location)
The column information in error messages was added in Visual Studio 2017. However, it is sometimes missing or incorrect.
- Missing column information is often because the compiler does not always propagate the column information between functions.
- Incorrect column information is sometimes produced because the compiler does not maintain the necessary information in nested contexts (e.g., instantiating a template specialization) and its value is incorrectly modified.
We are continuing to audit the APIs which manipulate the source location to make sure they propagate and maintain the column information.
There are still cases where the column information is incorrect in the first place (which is common in the compiler generated functions), so if you hit any of these, please let us know!
The error messages for overload resolution vary depending on whether the function is a global function or a member function, whether it is an operator or not, and is sensitive to the number of available candidates. This causes inconsistencies like:
- The compiler often only lists the last candidate it tried.
- The compiler sometimes lists all candidates, but without explaining why each candidate fails.
- The compiler often ignores template candidates.
We now align the behavior in these scenarios to be more consistent: we always list all candidates including the template and explain why each candidate fails.
Concept (unsatisfied associated constraints)
Previously, the compiler only emitted one general purpose message for unsatisfied associated constraints.
Now, the compiler will emit all the associated constraints which contribute to a given failure. Some of them will have an explanation while others will not.
We are still working on the latter because most of our semantics analysis logic does not propagate the reasons back to the caller yet – the constraint validation logic only knows that something failed.
Call for action
As always, we welcome your feedback. Feel free to send any comments through e-mail at [email protected] or through Twitter @visualc.
If you encounter other problems with MSVC in VS 2019/2022 please let us know via the Report a Problem option, either from the installer or the Visual Studio IDE itself. For suggestions or bug reports, let us know through DevComm.