Skip to content

Commit e4d0659

Browse files
Fix Issue 22384 - Add support for default values in C-style bitfields
This implements parsing, semantic analysis, and backend support for default initializers in bitfields. - Modified 'declaration.d' & 'parse.d' to parse assignment expressions after bitfield width. - Implemented semantic cheks in 'semantic2.d' using IntRange for bound validation. - Updated 'todt.d' to pack default values into the binary representation. - Added regression tests.
1 parent e64c0a4 commit e4d0659

File tree

6 files changed

+119
-8
lines changed

6 files changed

+119
-8
lines changed

compiler/src/dmd/declaration.d

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -663,9 +663,9 @@ extern (C++) class BitFieldDeclaration : VarDeclaration
663663
uint fieldWidth;
664664
uint bitOffset;
665665

666-
final extern (D) this(Loc loc, Type type, Identifier ident, Expression width)
666+
final extern (D) this(Loc loc, Type type, Identifier ident, Expression width, Initializer _init = null)
667667
{
668-
super(loc, type, ident, null);
668+
super(loc, type, ident, _init);
669669
this.dsym = DSYM.bitFieldDeclaration;
670670
this.width = width;
671671
this.storage_class |= STC.field;
@@ -675,7 +675,7 @@ extern (C++) class BitFieldDeclaration : VarDeclaration
675675
{
676676
//printf("BitFieldDeclaration::syntaxCopy(%s)\n", toChars());
677677
assert(!s);
678-
auto bf = new BitFieldDeclaration(loc, type ? type.syntaxCopy() : null, ident, width.syntaxCopy());
678+
auto bf = new BitFieldDeclaration(loc, type ? type.syntaxCopy() : null, ident, width.syntaxCopy(), _init ? _init.syntaxCopy() : null);
679679
bf.comment = comment;
680680
return bf;
681681
}

compiler/src/dmd/glue/todt.d

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1002,13 +1002,32 @@ private void membersToDt(AggregateDeclaration ad, ref DtBuilder dtb,
10021002
auto value = ie.getInteger();
10031003
const width = bf.fieldWidth;
10041004
const mask = (1L << width) - 1;
1005-
bitFieldValue = (bitFieldValue & ~(mask << bitOffset)) | ((value & mask) << bitOffset);
1005+
bitFieldValue = (bitFieldValue & ~(mask << bf.bitOffset)) | ((value & mask) << bf.bitOffset);
10061006
//printf("bitFieldValue x%llx\n", bitFieldValue);
10071007
}
10081008
else
10091009
Expression_toDt(e, dtbx); // convert e to an initializer dt
10101010
}
1011-
else if (!bf)
1011+
else if (bf)
1012+
{
1013+
if (Initializer init = vd._init)
1014+
{
1015+
if (init.isVoidInitializer())
1016+
continue;
1017+
1018+
assert(vd.semanticRun >= PASS.semantic2done);
1019+
auto ei = init.isExpInitializer();
1020+
assert(ei);
1021+
auto ie = ei.exp.isIntegerExp();
1022+
assert(ie);
1023+
1024+
auto value = ie.getInteger();
1025+
const width = bf.fieldWidth;
1026+
const mask = (1L << width) - 1;
1027+
bitFieldValue = (bitFieldValue & ~(mask << bf.bitOffset)) | ((value & mask) << bf.bitOffset);
1028+
}
1029+
}
1030+
else
10121031
{
10131032
if (Initializer init = vd._init)
10141033
{

compiler/src/dmd/parse.d

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4792,11 +4792,9 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
47924792
AST.Dsymbol s;
47934793
if (width)
47944794
{
4795-
if (_init)
4796-
error("initializer not allowed for bitfield declaration");
47974795
if (storage_class)
47984796
error("storage class not allowed for bitfield declaration");
4799-
s = new AST.BitFieldDeclaration(width.loc, t, ident, width);
4797+
s = new AST.BitFieldDeclaration(width.loc, t, ident, width, _init);
48004798
}
48014799
else
48024800
{

compiler/src/dmd/semantic2.d

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ import dmd.nogc;
5353
import dmd.nspace;
5454
import dmd.objc;
5555
import dmd.opover;
56+
import dmd.optimize;
5657
import dmd.parse;
5758
import dmd.root.filename;
5859
import dmd.common.outbuffer;
@@ -320,6 +321,41 @@ private extern(C++) final class Semantic2Visitor : Visitor
320321
vd.semanticRun = PASS.semantic2done;
321322
}
322323

324+
override void visit(BitFieldDeclaration bfd)
325+
{
326+
visit(cast(VarDeclaration)bfd);
327+
if (bfd.semanticRun != PASS.semantic2done)
328+
return;
329+
330+
if (!bfd._init)
331+
return;
332+
333+
auto ei = bfd._init.isExpInitializer();
334+
if (!ei)
335+
return;
336+
337+
ei.exp = ei.exp.optimize(WANTvalue);
338+
auto e = ei.exp;
339+
if (!e.isIntegerExp())
340+
return;
341+
342+
import dmd.intrange;
343+
auto value = getIntRange(e);
344+
345+
const bool isUnsigned = bfd.type.isUnsigned();
346+
auto bounds = IntRange(
347+
SignExtendedNumber(bfd.getMinMax(Id.min), !isUnsigned),
348+
SignExtendedNumber(bfd.getMinMax(Id.max), false)
349+
);
350+
351+
if (!bounds.contains(value))
352+
{
353+
const uwidth = bfd.fieldWidth;
354+
error(bfd.loc, "bitfield initializer `%s` does not fit in %d bit%s",
355+
e.toChars(), cast(int) uwidth, uwidth == 1 ? "".ptr : "s".ptr);
356+
}
357+
}
358+
323359
override void visit(Module mod)
324360
{
325361
//printf("Module::semantic2('%s'): parent = %p\n", toChars(), parent);
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/*
2+
TEST_OUTPUT:
3+
---
4+
fail_compilation/fail22384.d(8): Error: bitfield initializer `4294967295u` does not fit in 4 bits
5+
---
6+
*/
7+
struct S {
8+
uint d : 4 = -1;
9+
}

compiler/test/runnable/test22384.d

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
//https://github.com/dlang/dmd/issues/22384
2+
struct S
3+
{
4+
int a = 1;
5+
int b : 16 = 2;
6+
int c : 16 = 3;
7+
int d = 4;
8+
}
9+
10+
struct T
11+
{
12+
int a = 1; // .long 1
13+
int b : 4 = 2; // .byte 0x32 (b=2, c=3 merged)
14+
int c : 4 = 3;
15+
int d : 8 = 4; // .byte 0x04
16+
int e : 4 = 5; // .byte 0x65 (e=5, f_low=6 merged)
17+
int f : 12 = 6; // .byte 0x00 (f_high)
18+
int g = 7; // .long 7
19+
}
20+
21+
struct M
22+
{
23+
int a : 4 = 1;
24+
int : 4;
25+
int b : 4 = 2;
26+
}
27+
28+
S s;
29+
T t;
30+
M m;
31+
32+
void main()
33+
{
34+
assert(s.a == 1);
35+
assert(s.b == 2);
36+
assert(s.c == 3);
37+
assert(s.d == 4);
38+
39+
assert(t.a == 1);
40+
assert(t.b == 2);
41+
assert(t.c == 3);
42+
assert(t.d == 4);
43+
assert(t.e == 5);
44+
assert(t.f == 6);
45+
assert(t.g == 7);
46+
47+
assert(m.a == 1);
48+
assert(m.b == 2);
49+
}

0 commit comments

Comments
 (0)