From ec34292ead8bb30bae9f779326c0931238c70e75 Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Sun, 26 Nov 2023 02:52:07 -0800 Subject: [PATCH] fix Issue 24262 - Assert error with bit fields (#15864) --- compiler/src/dmd/e2ir.d | 59 +++++++++++++++++++++--------- compiler/test/runnable/bitfields.c | 29 +++++++++++++++ 2 files changed, 70 insertions(+), 18 deletions(-) diff --git a/compiler/src/dmd/e2ir.d b/compiler/src/dmd/e2ir.d index 63eba003c7..8b118676e0 100644 --- a/compiler/src/dmd/e2ir.d +++ b/compiler/src/dmd/e2ir.d @@ -6522,13 +6522,13 @@ elem *toElemStructLit(StructLiteralExp sle, ref IRState irs, EXP op, Symbol *sym // CTFE may fill the hidden pointer by NullExp. { VarDeclaration vbf; - foreach (i, el; *sle.elements) + foreach (i, element; *sle.elements) { - if (!el) + if (!element) continue; VarDeclaration v = sle.sd.fields[i]; - assert(!v.isThisDeclaration() || el.op == EXP.null_); + assert(!v.isThisDeclaration() || element.op == EXP.null_); elem *e1; if (tybasic(stmp.Stype.Tty) == TYnptr) @@ -6539,50 +6539,73 @@ elem *toElemStructLit(StructLiteralExp sle, ref IRState irs, EXP op, Symbol *sym { e1 = el_ptr(stmp); } - e1 = el_bin(OPadd, TYnptr, e1, el_long(TYsize_t, v.offset)); - elem *ep = toElem(el, irs); + elem *ep = toElem(element, irs); Type t1b = v.type.toBasetype(); - Type t2b = el.type.toBasetype(); + Type t2b = element.type.toBasetype(); if (t1b.ty == Tsarray) { + e1 = el_bin(OPadd, TYnptr, e1, el_long(TYsize_t, v.offset)); if (t2b.implicitConvTo(t1b)) { elem *esize = el_long(TYsize_t, t1b.size()); - ep = array_toPtr(el.type, ep); + ep = array_toPtr(element.type, ep); e1 = el_bin(OPmemcpy, TYnptr, e1, el_param(ep, esize)); } else { elem *edim = el_long(TYsize_t, t1b.size() / t2b.size()); - e1 = setArray(el, e1, edim, t2b, ep, irs, op == EXP.construct ? EXP.blit : op); + e1 = setArray(element, e1, edim, t2b, ep, irs, op == EXP.construct ? EXP.blit : op); } } else { - tym_t ty = totym(v.type); - e1 = el_una(OPind, ty, e1); - if (tybasic(ty) == TYstruct) + const tym_t tym = totym(v.type); + auto voffset = v.offset; + uint bitfieldArg; + uint bitOffset; + auto bf = v.isBitFieldDeclaration(); + if (bf) + { + const szbits = tysize(tym) * 8; + bitOffset = bf.bitOffset; + if (bitOffset + bf.fieldWidth > szbits) + { + const advance = bitOffset / szbits; + voffset += advance; + bitOffset -= advance * 8; + assert(bitOffset + bf.fieldWidth <= szbits); + } + bitfieldArg = bf.fieldWidth * 256 + bitOffset; + + //printf("2bitOffset %u fieldWidth %u bits %u\n", bitOffset, bf.fieldWidth, szbits); + assert(bitOffset + bf.fieldWidth <= szbits); + } + + e1 = el_bin(OPadd, TYnptr, e1, el_long(TYsize_t, voffset)); + e1 = el_una(OPind, tym, e1); + if (tybasic(tym) == TYstruct) + { e1.ET = Type_toCtype(v.type); - if (auto bf = v.isBitFieldDeclaration()) + assert(!bf); + } + if (bf) { if (!vbf || vbf.offset + vbf.type.size() <= v.offset) { /* Initialize entire location the bitfield is in * ep = (ep & ((1 << bf.fieldWidth) - 1)) << bf.bitOffset */ - tym_t e1ty = e1.Ety; - auto ex = el_bin(OPand, e1ty, ep, el_long(e1ty, (1L << bf.fieldWidth) - 1)); - ep = el_bin(OPshl, e1ty, ex, el_long(e1ty, bf.bitOffset)); + auto ex = el_bin(OPand, tym, ep, el_long(tym, (1L << bf.fieldWidth) - 1)); + ep = el_bin(OPshl, tym, ex, el_long(tym, bitOffset)); vbf = v; } else { - // Insert special bitfield operator - auto mos = el_long(TYuint, bf.fieldWidth * 256 + bf.bitOffset); //printf("2bitOffset %u fieldWidth %u bits %u\n", bf.bitOffset, bf.fieldWidth, tysize(e1.Ety) * 8); - assert(bf.bitOffset + bf.fieldWidth <= tysize(e1.Ety) * 8); + // Insert special bitfield operator + auto mos = el_long(TYuint, bitfieldArg); e1 = el_bin(OPbit, e1.Ety, e1, mos); } } diff --git a/compiler/test/runnable/bitfields.c b/compiler/test/runnable/bitfields.c index 8946c83257..20ff397a90 100644 --- a/compiler/test/runnable/bitfields.c +++ b/compiler/test/runnable/bitfields.c @@ -254,6 +254,34 @@ _Static_assert(test7s2() == -2, "3"); /******************************************/ +// https://issues.dlang.org/show_bug.cgi?id=24257 + +#include + +struct Entry +{ + unsigned id : 15; + _Bool done : 1; +}; + +struct State +{ + struct Entry e; +}; + +void test24257() +{ + int i = 72; + struct State s = (struct State){i}; + if (s.e.id != 72) + { + printf("error %d\n", __LINE__); + exit(1); + } +} + +/******************************************/ + int main() { test1(); @@ -263,6 +291,7 @@ int main() test5(); test6(); test7(); + test24257(); return 0; }