Handle new extern(C) structs with size 0

The linkage now (2.098) also affects the size of empty structs - e.g.,
1 for extern(C++), 0 for Posix extern(C), 4 for MSVC extern(C).

This also affects beauties like `extern(C) struct S { double[0] a; }`,
as tested by dmd-testsuite's runnable/ldc_cabi1.d, which is hereby
fixed for Posix - don't try to GEP into an empty LL struct.
This commit is contained in:
Martin Kinkelin 2021-09-08 23:28:44 +02:00
parent 4fd476da9a
commit db4867d437
2 changed files with 17 additions and 14 deletions

View file

@ -1844,27 +1844,32 @@ LLValue *DtoIndexAggregate(LLValue *src, AggregateDeclaration *ad,
// ourselves, DtoType below would be enough.
DtoResolveDsymbol(ad);
// Cast the pointer we got to the canonical struct type the indices are
// based on.
LLType *st = DtoType(ad->type);
if (ad->isStructDeclaration()) {
st = getPtrToType(st);
}
src = DtoBitCast(src, st);
// Look up field to index and any offset to apply.
// Look up field to index or offset to apply.
unsigned fieldIndex;
unsigned byteOffset;
auto irTypeAggr = getIrType(ad->type)->isAggr();
assert(irTypeAggr);
irTypeAggr->getMemberLocation(vd, fieldIndex, byteOffset);
LLValue *val = DtoGEP(src, 0, fieldIndex);
LLValue *val = src;
if (byteOffset) {
// Cast to void* to apply byte-wise offset.
assert(fieldIndex == 0);
// Cast to void* to apply byte-wise offset from object start.
val = DtoBitCast(val, getVoidPtrType());
val = DtoGEP1(val, byteOffset);
} else {
if (ad->structsize == 0) { // can happen for extern(C) structs
assert(fieldIndex == 0);
} else {
// Cast the pointer we got to the canonical struct type the indices are
// based on.
LLType *st = DtoType(ad->type);
if (ad->isStructDeclaration()) {
st = getPtrToType(st);
}
val = DtoBitCast(val, st);
val = DtoGEP(val, 0, fieldIndex);
}
}
// Cast the (possibly void*) pointer to the canonical variable type.