From c94d462cb9f9c3863ed7e2357453d242f9c7c5dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C4=81vis=20Mos=C4=81ns?= Date: Sat, 20 Jun 2026 21:06:53 +0300 Subject: [PATCH 1/3] Rewrite bit field parsing to use D native bitfields instead of std.bitmanip.bitfields This is necessary so that D struct layouts match exactly with C layouts. If we would use std.bitmanip.bitfields then it's layout wouldn't match C. It is possible to implement std.bitmanip.bitfields in a way to match C layout but that's a lot of quite complex code. --- dstep/translator/Record.d | 90 ++++--------------------------------- tests/unit/BitFieldsTests.d | 85 ++++++++++------------------------- 2 files changed, 33 insertions(+), 142 deletions(-) diff --git a/dstep/translator/Record.d b/dstep/translator/Record.d index f22c758c..1e299f5a 100644 --- a/dstep/translator/Record.d +++ b/dstep/translator/Record.d @@ -35,62 +35,6 @@ void translatePackedAttribute(Output output, Context context, Cursor cursor) output.singleLine("align (1):"); } -struct BitField -{ - string type; - string field; - uint width; -} - -BitField[] translateBitFields( - Context context, - Cursor[] cursors) -{ - static void pad(ref BitField[] bitFields, uint totalWidth) - { - uint padding = 0; - - for (uint size = 8; size <= 64; size *= 2) - { - if (totalWidth <= size) - { - padding = size - totalWidth; - break; - } - } - - if (padding != 0) - bitFields ~= BitField("uint", "", padding); - } - - BitField[] bitFields; - uint totalWidth = 0; - - foreach (cursor; cursors) - { - auto width = cursor.bitFieldWidth(); - - if (width == 0) - { - pad(bitFields, totalWidth); - totalWidth = 0; - } - else - { - bitFields ~= BitField( - translateType(context, cursor).makeString(), - cursor.spelling(), - width); - - totalWidth += width; - } - } - - pad(bitFields, totalWidth); - - return bitFields; -} - void translateBitFields( Output output, Context context, @@ -98,31 +42,18 @@ void translateBitFields( { import std.range; - auto bitFields = translateBitFields(context, cursors); + assert(cursors.length > 0); - if (bitFields.length == 1) + foreach (cursor; cursors) { - auto bitField = bitFields.front; + auto type = translateType(context, cursor).makeString(); + auto name = cursor.spelling(); + auto width = cursor.bitFieldWidth(); - output.singleLine( - `mixin(bitfields!(%s, "%s", %s));`, - bitField.type, - bitField.field, - bitField.width); - } - else - { - output.multiLine("mixin(bitfields!(") in { - foreach (index, bitField; enumerate(bitFields)) - { - output.singleLine( - `%s, "%s", %s%s`, - bitField.type, - bitField.field, - bitField.width, - index + 1 == bitFields.length ? "));" : ","); - } - }; + if (name.empty) + output.singleLine("%s : %d;", type, width); + else + output.singleLine("%s %s : %d;", type, name, width); } } @@ -160,9 +91,6 @@ void translateRecordDef( auto declarations = cursor.children .filter!(cursor => cursor.isDeclaration)(); - if (declarations.any!(cursor => cursor.isBitField())) - output.singleLine("import std.bitmanip : bitfields;"); - translatePackedAttribute(output, context, cursor); foreach (chunk; declarations.chunkBy!predicate()) diff --git a/tests/unit/BitFieldsTests.d b/tests/unit/BitFieldsTests.d index 6dfce103..43fa17aa 100644 --- a/tests/unit/BitFieldsTests.d +++ b/tests/unit/BitFieldsTests.d @@ -21,11 +21,7 @@ extern (C): struct Foo { - import std.bitmanip : bitfields; - - mixin(bitfields!( - int, "x", 4, - uint, "", 4)); + int x : 4; } D"); @@ -44,8 +40,7 @@ extern (C): struct Foo { - import std.bitmanip : bitfields; - mixin(bitfields!(int, "x", 8)); + int x : 8; } D"); @@ -65,12 +60,9 @@ extern (C): struct bitfield { - import std.bitmanip : bitfields; - - mixin(bitfields!( - uint, "one", 4, - uint, "two", 8, - uint, "", 4)); + uint one : 4; + uint two : 8; + uint : 4; } D"); } @@ -86,14 +78,10 @@ extern (C): struct Foo { - import std.bitmanip : bitfields; - - mixin(bitfields!( - ubyte, "a", 3, - ubyte, "", 2, - ubyte, "b", 6, - ubyte, "c", 2, - uint, "", 3)); + ubyte a : 3; + ubyte : 2; + ubyte b : 6; + ubyte c : 2; } D"); @@ -111,11 +99,7 @@ extern (C): struct Foo { - import std.bitmanip : bitfields; - - mixin(bitfields!( - short, "a", 4, - uint, "", 4)); + short a : 4; char b; } @@ -136,13 +120,8 @@ extern (C): struct Foo { - import std.bitmanip : bitfields; - short a; - - mixin(bitfields!( - char, "b", 7, - uint, "", 1)); + char b : 7; char[1] c; } @@ -165,16 +144,11 @@ extern (C): struct Foo { - import std.bitmanip : bitfields; - short a; char b; - - mixin(bitfields!( - int, "c", 1, - int, "d", 4, - int, "e", 7, - uint, "", 4)); + int c : 1; + int d : 4; + int e : 7; } D"); @@ -197,17 +171,12 @@ extern (C): struct Foo { - import std.bitmanip : bitfields; - short a; - - mixin(bitfields!( - int, "b", 1, - int, "c", 4, - int, "d", 3, - int, "e", 7, - int, "f", 25, - uint, "", 24)); + int b : 1; + int c : 4; + int d : 3; + int e : 7; + int f : 25; char g; } @@ -235,20 +204,14 @@ extern (C): struct Foo { - import std.bitmanip : bitfields; - short a; - - mixin(bitfields!( - int, "b", 1, - int, "c", 4, - int, "d", 3)); + int b : 1; + int c : 4; + int d : 3; c_long e; - - mixin(bitfields!( - int, "f", 7, - int, "g", 25)); + int f : 7; + int g : 25; char h; } From 974909b5dc93d75b8ebdfe42aa6922037afef682 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C4=81vis=20Mos=C4=81ns?= Date: Sat, 20 Jun 2026 21:22:07 +0300 Subject: [PATCH 2/3] Add additional tests --- tests/unit/BitFieldsTests.d | 71 +++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/tests/unit/BitFieldsTests.d b/tests/unit/BitFieldsTests.d index 43fa17aa..ad6e7b78 100644 --- a/tests/unit/BitFieldsTests.d +++ b/tests/unit/BitFieldsTests.d @@ -218,3 +218,74 @@ struct Foo D"); }; + +unittest +{ + assertTranslates(q"C +struct Foo { + unsigned int a : 16; + unsigned int b : 16; + unsigned int c : 8; + unsigned int d : 8; + unsigned int e : 16; + unsigned long long f : 42; +}; +C",q"D +extern (C): + +struct Foo +{ + uint a : 16; + uint b : 16; + uint c : 8; + uint d : 8; + uint e : 16; + ulong f : 42; +} +D"); + +} + +unittest +{ + assertTranslates(q"C +struct Foo { + int a : 4; + int b : 8; + int c : 12; +}; +C",q"D +extern (C): + +struct Foo +{ + int a : 4; + int b : 8; + int c : 12; +} +D"); + +} + +unittest +{ + assertTranslates(q"C +struct Foo { + int a : 1; + int b : 1; + int c : 1; + int d : 1; +}; +C",q"D +extern (C): + +struct Foo +{ + int a : 1; + int b : 1; + int c : 1; + int d : 1; +} +D"); + +} From 901b0a7472a339641b5be0e190742901a2a21f96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C4=81vis=20Mos=C4=81ns?= Date: Sun, 21 Jun 2026 02:14:07 +0300 Subject: [PATCH 3/3] Add partial support for __int128 (not compatible with C) --- dstep/translator/Record.d | 14 +++++++++++--- tests/unit/BitFieldsTests.d | 26 ++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/dstep/translator/Record.d b/dstep/translator/Record.d index 1e299f5a..f8cc4383 100644 --- a/dstep/translator/Record.d +++ b/dstep/translator/Record.d @@ -49,11 +49,19 @@ void translateBitFields( auto type = translateType(context, cursor).makeString(); auto name = cursor.spelling(); auto width = cursor.bitFieldWidth(); + auto typeWidth = cast(uint)(cursor.type.sizeOf * 8); - if (name.empty) - output.singleLine("%s : %d;", type, width); + if (typeWidth > 64) + { + output.singleLine("%s %s; // only %s bits used, struct's layout incompatible with C", type, name, width); + } else - output.singleLine("%s %s : %d;", type, name, width); + { + if (name.empty) + output.singleLine("%s : %d;", type, width); + else + output.singleLine("%s %s : %d;", type, name, width); + } } } diff --git a/tests/unit/BitFieldsTests.d b/tests/unit/BitFieldsTests.d index ad6e7b78..9598f903 100644 --- a/tests/unit/BitFieldsTests.d +++ b/tests/unit/BitFieldsTests.d @@ -289,3 +289,29 @@ struct Foo D"); } + +// Known limitation that layout won't match C +// Incredibly complex to get this right so leaving like this +unittest +{ + assertTranslates(q"C +struct Foo +{ + __int128 a : 50; + int b : 10; + __int128 c : 62; +}; +C",q"D +import core.int128; + +extern (C): + +struct Foo +{ + Cent a; // only 50 bits used, struct's layout incompatible with C + int b : 10; + Cent c; // only 62 bits used, struct's layout incompatible with C +} +D"); + +}