Skip to content

Commit 54f6bb9

Browse files
committed
add bitfields to D
1 parent a77f4ad commit 54f6bb9

File tree

8 files changed

+123
-18
lines changed

8 files changed

+123
-18
lines changed

changelog/bitfields.dd

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
Add bit fields to D
2+
3+
They work just like the bit fields in ImportC do.
4+
5+
https://github.com/dlang/dlang.org/pull/3190
6+
7+
---
8+
struct B
9+
{
10+
int x:3, y:2;
11+
}
12+
13+
static assert(B.sizeof == 4);
14+
15+
int vaporator(B b)
16+
{
17+
b.x = 4;
18+
b.y = 2;
19+
return b.x + b.y; // returns 6
20+
}
21+
---

src/dmd/dsymbolsem.d

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1229,6 +1229,11 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
12291229
if (dsym.errors)
12301230
return;
12311231

1232+
if (!dsym.parent.isStructDeclaration() && !dsym.parent.isClassDeclaration())
1233+
{
1234+
dsym.error("bit-field must be member of struct, union, or class");
1235+
}
1236+
12321237
sc = sc.startCTFE();
12331238
auto width = dsym.width.expressionSemantic(sc);
12341239
sc = sc.endCTFE();

src/dmd/parse.d

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,15 @@ class Parser(AST) : Lexer
496496
return true;
497497
}
498498

499+
/************************************
500+
* Parse declarations and definitions
501+
* Params:
502+
* once = !=0 means parse exactly one decl or def
503+
* pLastDecl = set to last decl or def parsed
504+
* pAttrs = keep track of attributes
505+
* Returns:
506+
* array of declared symbols
507+
*/
499508
AST.Dsymbols* parseDeclDefs(int once, AST.Dsymbol* pLastDecl = null, PrefixAttributes!AST* pAttrs = null)
500509
{
501510
AST.Dsymbol lastDecl = null; // used to link unittest to its previous declaration
@@ -4496,7 +4505,8 @@ class Parser(AST) : Lexer
44964505
* These can be:
44974506
* 1. declarations at global/class level
44984507
* 2. declarations at statement level
4499-
* Return array of Declaration *'s.
4508+
* Returns:
4509+
* array of Declarations.
45004510
*/
45014511
private AST.Dsymbols* parseDeclarations(bool autodecl, PrefixAttributes!AST* pAttrs, const(char)* comment)
45024512
{
@@ -4653,6 +4663,12 @@ class Parser(AST) : Lexer
46534663
else if (t != tfirst)
46544664
error("multiple declarations must have the same type, not `%s` and `%s`", tfirst.toChars(), t.toChars());
46554665

4666+
if (token.value == TOK.colon && !ident && t.ty != Tfunction)
4667+
{
4668+
// Unnamed bit field
4669+
ident = Identifier.generateAnonymousId("BitField");
4670+
}
4671+
46564672
bool isThis = (t.ty == Tident && (cast(AST.TypeIdentifier)t).ident == Id.This && token.value == TOK.assign);
46574673
if (ident)
46584674
checkCstyleTypeSyntax(loc, t, alt, ident);
@@ -4785,19 +4801,37 @@ class Parser(AST) : Lexer
47854801
}
47864802
else if (ident)
47874803
{
4804+
AST.Expression width;
4805+
if (token.value == TOK.colon)
4806+
{
4807+
nextToken();
4808+
width = parseCondExp();
4809+
}
4810+
47884811
AST.Initializer _init = null;
47894812
if (token.value == TOK.assign)
47904813
{
47914814
nextToken();
47924815
_init = parseInitializer();
47934816
}
47944817

4795-
auto v = new AST.VarDeclaration(loc, t, ident, _init);
4796-
v.storage_class = storage_class;
4797-
if (pAttrs)
4798-
pAttrs.storageClass = STC.undefined_;
4799-
4800-
AST.Dsymbol s = v;
4818+
AST.Dsymbol s;
4819+
if (width)
4820+
{
4821+
if (_init)
4822+
error("no initializer for bit-field declaration");
4823+
if (storage_class)
4824+
error("no storage class for bit-field declaration");
4825+
s = new AST.BitFieldDeclaration(width.loc, t, ident, width);
4826+
}
4827+
else
4828+
{
4829+
auto v = new AST.VarDeclaration(loc, t, ident, _init);
4830+
v.storage_class = storage_class;
4831+
if (pAttrs)
4832+
pAttrs.storageClass = STC.undefined_;
4833+
s = v;
4834+
}
48014835

48024836
if (tpl && _init)
48034837
{
@@ -4810,7 +4844,7 @@ class Parser(AST) : Lexer
48104844
{
48114845
auto ax = new AST.Dsymbols();
48124846
ax.push(s);
4813-
s = new AST.AlignDeclaration(v.loc, ealign, ax);
4847+
s = new AST.AlignDeclaration(s.loc, ealign, ax);
48144848
}
48154849
if (link != linkage)
48164850
{
@@ -4840,12 +4874,12 @@ class Parser(AST) : Lexer
48404874
default:
48414875
if (loc.linnum != token.loc.linnum)
48424876
{
4843-
error("semicolon needed to end declaration of `%s`, instead of `%s`", v.toChars(), token.toChars());
4844-
errorSupplemental(loc, "`%s` declared here", v.toChars());
4877+
error("semicolon needed to end declaration of `%s`, instead of `%s`", s.toChars(), token.toChars());
4878+
errorSupplemental(loc, "`%s` declared here", s.toChars());
48454879
}
48464880
else
48474881
{
4848-
error("semicolon needed to end declaration of `%s` instead of `%s`", v.toChars(), token.toChars());
4882+
error("semicolon needed to end declaration of `%s` instead of `%s`", s.toChars(), token.toChars());
48494883
}
48504884
break;
48514885
}

test/fail_compilation/biterrors.d

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/* TEST_OUTPUT:
2+
---
3+
fail_compilation/biterrors.d(103): Error: no initializer for bit-field declaration
4+
fail_compilation/biterrors.d(104): Error: no storage class for bit-field declaration
5+
---
6+
*/
7+
8+
#line 100
9+
10+
struct S
11+
{
12+
int i : 3 = 7;
13+
static int j : 3;
14+
}

test/fail_compilation/biterrors2.d

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/* TEST_OUTPUT:
2+
---
3+
fail_compilation/biterrors2.d(100): Error: variable `biterrors2.a` bit-field must be member of struct, union, or class
4+
---
5+
*/
6+
7+
#line 100
8+
int a : 2;

test/fail_compilation/test16188.d

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
TEST_OUTPUT:
1+
/* TEST_OUTPUT:
22
---
3-
fail_compilation/test16188.d(1): Error: no identifier for declarator `TEST_OUTPUT`
4-
fail_compilation/test16188.d(1): Error: declaration expected, not `:`
5-
fail_compilation/test16188.d(18): Error: unmatched closing brace
3+
fail_compilation/test16188.d(101): Error: no property `name` for type `test16188.Where`
4+
fail_compilation/test16188.d(101): potentially malformed `opDispatch`. Use an explicit instantiation to get a better error message
65
---
76
*/
87

@@ -15,6 +14,8 @@ fail_compilation/test16188.d(18): Error: unmatched closing brace
1514
* I don't understand why.
1615
*/
1716

17+
#line 100
18+
1819
void where() { Where().name; }
1920

2021
struct Where

test/fail_compilation/test17284.d

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
TEST_OUTPUT:
22
---
3-
fail_compilation/test17284.d(1): Error: no identifier for declarator `TEST_OUTPUT`
4-
fail_compilation/test17284.d(1): Error: declaration expected, not `:`
5-
fail_compilation/test17284.d(12): Error: unmatched closing brace
3+
fail_compilation/test17284.d(3): Error: semicolon needed to end declaration of `__anonBitField1`, instead of `:`
4+
fail_compilation/test17284.d(1): `__anonBitField1` declared here
5+
fail_compilation/test17284.d(3): Error: declaration expected, not `:`
6+
fail_compilation/test17284.d(13): Error: unmatched closing brace
67
---
78
*/
89

test/runnable/bit.d

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
2+
struct S
3+
{
4+
uint x : 2, y : 3, :0;
5+
int :0;
6+
}
7+
8+
uint foo(S s)
9+
{
10+
return s.x + s.y;
11+
}
12+
13+
int main()
14+
{
15+
S s;
16+
s.x = 2;
17+
s.y = 4;
18+
uint u = foo(s);
19+
assert(u == 6);
20+
return 0;
21+
}

0 commit comments

Comments
 (0)