The Future of C++ Compiler Diagnostics in MSVC and Visual Studio

Xiang Fan

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.

In-box viewer

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.

Compiler changes

  1. The last message for template instantiation contexts now displays the text column which the error occurred at.
  2. The compiler now lists all candidates for a function call and explains why each candidate fails.
  3. The error message for unsatisfied associated constraints is expanded to detail which underlying constraints were not satisfied.

Source code

#include <concepts>

struct functor
{
    template <std::integral T>
    void operator()(T);
    void operator()(int*);
    void operator()(long*);
};

template<typename T>
void test(T t)
{
    functor f;
    f(t);
}

int main()
{
    test(1.0);
}

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<double>(T)' being compiled
        with
        [
            T=double
        ]
        test(1.0);

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<double>' evaluated to false
        template <std::integral T>
                  ^
concepts(81,20): note: the constraint was not satisfied
concept integral = is_integral_v<_Ty>;
                   ^
example.cpp(15,2): note: while trying to match the argument list '(T)'
        with
        [
            T=double
        ]
        f(t);
        ^
example.cpp(20,10): note: see reference to function template instantiation 'void test<double>(T)' being compiled
        with
        [
            T=double
        ]
        test(1.0);
                ^

IDE changes

IDE experience in 17.4 (in-box viewer)

In-box viewer

IDE experience in 17.4 (SARIF viewer extension)

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.

Technical details

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!

Overload resolution

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 visualcpp@microsoft.com 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.

5 comments

Discussion is closed. Login to edit/delete existing comments.

  • Chris Green 0

    Does it sort the trial overloads to show the one with the fewest parameter mismatches first?

    • Xiang FanMicrosoft employee 0

      Hi, Chris:
      The compiler stores the candidates in a vector and lists them by iterating the vector. The order is sensitive to how function symbols are represented internally in the compiler and how argument dependent lookup (ADL) finds candidates.
      It is possible to have some heuristics to guess which candidate the developer intends to call. But there isn’t an easy and one-fits-all rule. This is something we will investigate in the future. For example, IntelliCode provides AI-assisted code completion suggestions by ‘guessing’ the function the developer wants to call (https://devblogs.microsoft.com/visualstudio/ai-assisted-intellisense-for-your-teams-codebase/).

  • Raymond Taylor 0

    This looks amazing, keep up the good work!

  • David Hunter 0

    Hi, I just tried the SARIF viewer extension in VS 17.4.0 Preview 3.0 and nothing appears in the SARIF explorer window when I click on an error.
    Your post says “We are experimenting with a new compiler option to output the diagnostics into the Static Analysis Results Interchange Format (SARIF)”.
    Does “we are working on” imply that this is not in 17.4.0 Preview 3.0 yet and that I can’t actually try this out or do I have to toggle some magic option to get this to happen? If it is not available generally yet is there an ETA?

    • Kyle ReedMicrosoft employee 0

      Hi,
      Are you talking about Static Analysis results or compiler errors/warnings?
      Static Analysis results should “just work” in 17.4 and if they aren’t, let us know.

      For the compiler errors, it’s still experimental. You can add a global project property (edit the vcxproj file) and set this property.

      <EnableExperimentalDiagnostics>true</EnableExperimentalDiagnostics>

      and you should start to see the new experimental error view.

Feedback usabilla icon