Skip to content

Commit a768a8c

Browse files
committed
add bitfields to D
1 parent 2aca68a commit a768a8c

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
@@ -4456,7 +4465,8 @@ class Parser(AST) : Lexer
44564465
* These can be:
44574466
* 1. declarations at global/class level
44584467
* 2. declarations at statement level
4459-
* Return array of Declaration *'s.
4468+
* Returns:
4469+
* array of Declarations.
44604470
*/
44614471
private AST.Dsymbols* parseDeclarations(bool autodecl, PrefixAttributes!AST* pAttrs, const(char)* comment)
44624472
{
@@ -4841,6 +4851,12 @@ class Parser(AST) : Lexer
48414851
else if (t != tfirst)
48424852
error("multiple declarations must have the same type, not `%s` and `%s`", tfirst.toChars(), t.toChars());
48434853

4854+
if (token.value == TOK.colon && !ident && t.ty != Tfunction)
4855+
{
4856+
// Unnamed bit field
4857+
ident = Identifier.generateAnonymousId("BitField");
4858+
}
4859+
48444860
bool isThis = (t.ty == Tident && (cast(AST.TypeIdentifier)t).ident == Id.This && token.value == TOK.assign);
48454861
if (ident)
48464862
checkCstyleTypeSyntax(loc, t, alt, ident);
@@ -4973,19 +4989,37 @@ class Parser(AST) : Lexer
49734989
}
49744990
else if (ident)
49754991
{
4992+
AST.Expression width;
4993+
if (token.value == TOK.colon)
4994+
{
4995+
nextToken();
4996+
width = parseCondExp();
4997+
}
4998+
49764999
AST.Initializer _init = null;
49775000
if (token.value == TOK.assign)
49785001
{
49795002
nextToken();
49805003
_init = parseInitializer();
49815004
}
49825005

4983-
auto v = new AST.VarDeclaration(loc, t, ident, _init);
4984-
v.storage_class = storage_class;
4985-
if (pAttrs)
4986-
pAttrs.storageClass = STC.undefined_;
4987-
4988-
AST.Dsymbol s = v;
5006+
AST.Dsymbol s;
5007+
if (width)
5008+
{
5009+
if (_init)
5010+
error("no initializer for bit-field declaration");
5011+
if (storage_class)
5012+
error("no storage class for bit-field declaration");
5013+
s = new AST.BitFieldDeclaration(width.loc, t, ident, width);
5014+
}
5015+
else
5016+
{
5017+
auto v = new AST.VarDeclaration(loc, t, ident, _init);
5018+
v.storage_class = storage_class;
5019+
if (pAttrs)
5020+
pAttrs.storageClass = STC.undefined_;
5021+
s = v;
5022+
}
49895023

49905024
if (tpl && _init)
49915025
{
@@ -4998,7 +5032,7 @@ class Parser(AST) : Lexer
49985032
{
49995033
auto ax = new AST.Dsymbols();
50005034
ax.push(s);
5001-
s = new AST.AlignDeclaration(v.loc, ealign, ax);
5035+
s = new AST.AlignDeclaration(s.loc, ealign, ax);
50025036
}
50035037
if (link != linkage)
50045038
{
@@ -5028,12 +5062,12 @@ class Parser(AST) : Lexer
50285062
default:
50295063
if (loc.linnum != token.loc.linnum)
50305064
{
5031-
error("semicolon needed to end declaration of `%s`, instead of `%s`", v.toChars(), token.toChars());
5032-
errorSupplemental(loc, "`%s` declared here", v.toChars());
5065+
error("semicolon needed to end declaration of `%s`, instead of `%s`", s.toChars(), token.toChars());
5066+
errorSupplemental(loc, "`%s` declared here", s.toChars());
50335067
}
50345068
else
50355069
{
5036-
error("semicolon needed to end declaration of `%s` instead of `%s`", v.toChars(), token.toChars());
5070+
error("semicolon needed to end declaration of `%s` instead of `%s`", s.toChars(), token.toChars());
50375071
}
50385072
break;
50395073
}

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)