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.
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 astatic_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!
}