#include <cstdint>
#include <type_traits>
extern "C"
{
struct thread_shared_struct
{
volatile uint32_t ccr;
};
struct thread_shared_struct getStuff();
}
static_assert(std::is_pod<thread_shared_struct>::value, "thread_shared_struct isn't a POD");
int main(int argc, char** argv)
{
thread_shared_struct m = getStuff();
return 0;
}
Of course this example doesn't make a lot of sense, but it is a minimal reproduction of my issue from a much larger code base.
With GCC (trunk) and Clang (trunk), this works fine.
With MSVC (x64, 19.22), the static_assert fails and getStuff() generates an error because it attempts to return a type that is not compatible with the C calling convention.
If "volatile" is removed, everything works fine.
Is MSVC in the wrong to think that thread_shared_struct is not a POD type?
The extern "C" part is in a C header that needs to stay as is. How could I use it from C++?
From the Microsoft documentation:
When a class or struct is both trivial and standard-layout, it is a POD (Plain Old Data) type.
It later describes literal types, including the following condition:
Additionally, all its non-static data members and base classes must be literal types and not volatile.
There is no mention of "volatile" anywhere else on the page.
This all matches what we find in the standard.
Therefore, I conclude it's a compiler bug.
getStuff() generates an error because it attempts to return a type that is not compatible with the C calling convention.
Actually, this is just a warning (C4190), which you could disable, if you wanted. Visual Studio on x86_64 only has one calling convention (described here). Your code will still work fine. VS is just warning you that the type won't work if you actually try to use it in C. extern "C"
does not mean compiling as C.
However, it is true that getting this warning suggests the bug is indeed in the compiler, rather than simply in the implementation of std::is_pod
.
Also, I would recommend avoiding POD terminology and the std::is_pod
trait in new code, since they are deprecated from C++20.
The extern "C" part is in a C header that needs to stay as is. How could I use it from C++?
Anything that doesn't actually require the type to fit VS's definition of "POD", type trait notwithstanding, should be fine.