Search code examples
visual-studiovisual-c++c++20visual-studio-2022stdmove

C++20 Compiler Error in Visual Studio 2022 Community: Resolving Internal Error C1001


I am facing an issue with C++20 in Visual Studio 2022 Community. The code works correctly in G++ but I get an internal compiler error with MSVC.

Here is the code:

#include <iostream>

struct Foo {
    float* data;

    Foo(float * const * const & address) :
        data(*address)
    {}

    Foo(float ** const && address) :
        data(*address)
    {}
};

int main() {
    int64_t size = 12;

    float* data = new float[size];
    float** address = &data;

    auto foo = Foo(std::move(address));
}

Error:

Build started...
1>------ Build started: Project: ConsoleApplication4, Configuration: Debug x64 ------
1>Scanning sources for module dependencies...
1>main.cpp
1>main.cpp(26,35): fatal  error C1001: Internal compiler error.
1>(compiler file 'msc1.cpp', line 1584)
1> To work around this problem, try simplifying or changing the program near the locations listed above.
1>If possible please provide a repro here: https://developercommunity.visualstudio.com
1>Please choose the Technical Support command on the Visual C++
1> Help menu, or open the Technical Support help file for more information
1>INTERNAL COMPILER ERROR in 'C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.35.32215\bin\HostX64\x64\CL.exe'
1>    Please choose the Technical Support command on the Visual C++
1>    Help menu, or open the Technical Support help file for more information
1>Done building project "ConsoleApplication4.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
========== Build started at 4:08 PM and took 01.716 seconds ==========

The error code is C1001, which suggests simplifying or changing the program. However, another project requires being able to differentiate between l-value and r-value pointers in a similar way. I would appreciate any assistance in resolving this issue.


Solution

  • Generally speaking, internal compiler errors aren't something that anyone outside the MSVC development team can really address, and the problem should be reported to that team.

    However, as a "quick fix", we can note that std::move(x) is equivalent to an appropriate static_cast<T&&>(x); from cppreference (bold emphasis mine):

    In particular, std::move produces an xvalue expression that identifies its argument t. It is exactly equivalent to a static_cast to an rvalue reference type.

    Thus, simply changing your std::move call to an equivalent cast makes MSVC happy:

    int main()
    {
        size_t size = 12; // Changed to "size_t" to be more correct!
    
        float* data = new float[size];
        float** address = &data;
    
    //  auto foo = Foo(std::move(address)); // fatal error C1001: Internal compiler error
        auto foo = Foo(static_cast<float** const&&>(address)); // MSVC happy and uses "rvalue c'tor"
    }
    

    Looking at this in more detail, I notice that the MSVC implementation of std::move<T> returns what a static_cast like the above yields, using the type that std::remove_reference<T>::type yields as the 'base type' for that cast. Here is the definition from the <type_traits> header:

    _EXPORT_STD template <class _Ty>
    _NODISCARD _MSVC_INTRINSIC constexpr remove_reference_t<_Ty>&& move(_Ty&& _Arg) noexcept {
        return static_cast<remove_reference_t<_Ty>&&>(_Arg);
    }
    

    What seems to be confusing the compiler here is the lack of a const qualifier on the address variable. Adding that also makes MSVC happy:

    int main()
    {
        size_t size = 12; // Changed to "size_t" to be more correct!
    
        float* data = new float[size];
        float** const address = &data; // Added the "const" qualifier here ...
    
        auto foo = Foo(std::move(address)); // ... and now MSVC is happy!
    }