dmd/compiler/test/runnable_cxx/testbitfields.d
Tim Schendekehl 4c82050e94 Fix bugzilla 24592 - ImportC: Bitfield layout wrong for int64 on 32-bit Linux
Type ulong is 64-bit on 32-bit Linux, but has 32-bit alignment.
This affects the layout of bitfields.

Also add a new test for ImportC bitfields, which compares size,
alignment and layout with the host C++ compiler. The existing
tests compared with fixed values instead.
2024-06-17 02:31:02 +02:00

90 lines
3 KiB
D

// EXTRA_CPP_SOURCES: testbitfields_cpp.cpp
// EXTRA_SOURCES: extra-files/testbitfields_importc.c
// CXXFLAGS(linux osx freebsd dragonflybsd): -std=c++11
import core.stdc.stdio;
import core.stdc.stdlib;
import core.stdc.string;
static import testbitfields_importc;
extern(C++) size_t getStructSize(T)();
extern(C++) size_t getStructAlign(T)();
extern(C++) void resetBitfield(T)(ref T data, const(char) *member);
bool checkType(S)()
{
bool different;
if (S.sizeof != getStructSize!S)
different = true;
if (S.alignof != getStructAlign!S)
different = true;
static foreach (member; __traits(allMembers, S))
{{
static if (member[0] != '_' && typeof(__traits(getMember, S, member)).stringof[0] != '_')
{
S dummyD;
memset(&dummyD, 0xff, S.sizeof);
__traits(getMember, dummyD, member) = 0;
S* dummyC = cast(S*) malloc(getStructSize!S);
memset(dummyC, 0xff, getStructSize!S);
resetBitfield!S(*dummyC, member.ptr);
if (S.sizeof == getStructSize!S && memcmp(&dummyD, dummyC, S.sizeof) != 0)
different = true;
free(dummyC);
}
}}
if (different)
{
printf("Struct %s has different bitfield layout for C and D:\n", __traits(identifier, S).ptr);
printf(" D: size=%zd align=%zd\n", S.sizeof, S.alignof);
printf(" C: size=%zd align=%zd\n", getStructSize!S, getStructAlign!S);
static foreach (member; __traits(allMembers, S))
{{
static if (member[0] != '_' && typeof(__traits(getMember, S, member)).stringof[0] != '_')
{
printf(" %s %s:\n", typeof(__traits(getMember, S, member)).stringof.ptr, member.ptr);
printf(" D:");
S dummyD;
memset(&dummyD, 0xff, S.sizeof);
__traits(getMember, dummyD, member) = 0;
foreach (i; 0 .. S.sizeof)
{
if (i % 4 == 0)
printf(" ");
printf("%02X", 0xff & ~(cast(ubyte*) &dummyD)[i]);
}
printf("\n C:");
S* dummyC = cast(S*) malloc(getStructSize!S);
memset(dummyC, 0xff, getStructSize!S);
resetBitfield!S(*dummyC, member.ptr);
foreach (i; 0 .. getStructSize!S)
{
if (i % 4 == 0)
printf(" ");
printf("%02X", 0xff & ~(cast(ubyte*) dummyC)[i]);
}
free(dummyC);
printf("\n");
}
}}
}
return different;
}
int main()
{
int ret;
static foreach (name; __traits(allMembers, testbitfields_importc))
{{
alias S = __traits(getMember, testbitfields_importc, name);
static if (is(S == struct) && name[0] != '_')
{
if (checkType!S)
ret = 1;
}
}}
return ret;
}