Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions changelog/dmd.bitfield-introspection.dd
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Add Bitfield Introspection Capability

Adds:

* property `.bitoffsetof` to get the starting bit number of a bitfield

* property `.bitwidth` to get the number of bits in a bitfield

* `__traits(isBitfield, symbol)` returns true if a field symbol is a bitfield
8 changes: 6 additions & 2 deletions compiler/src/dmd/expressionsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -14306,14 +14306,16 @@ private Expression dotIdSemanticPropX(DotIdExp exp, Scope* sc)

if (auto te = exp.e1.isTupleExp())
{
if (exp.ident == Id.offsetof)
if (exp.ident == Id.offsetof ||
exp.ident == Id.bitoffsetof ||
exp.ident == Id.bitwidth)
{
/* 'distribute' the .offsetof to each of the tuple elements.
*/
auto exps = new Expressions(te.exps.length);
foreach (i, e; (*te.exps)[])
{
(*exps)[i] = new DotIdExp(e.loc, e, Id.offsetof);
(*exps)[i] = new DotIdExp(e.loc, e, exp.ident);
}
// Don't evaluate te.e0 in runtime
Expression e = new TupleExp(exp.loc, null, exps);
Expand Down Expand Up @@ -14636,6 +14638,8 @@ Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, bool gag)
!cfile &&
(exp.ident == Id._mangleof ||
exp.ident == Id.offsetof ||
exp.ident == Id.bitoffsetof ||
exp.ident == Id.bitwidth ||
exp.ident == Id._init ||
exp.ident == Id.stringof)
))
Expand Down
3 changes: 3 additions & 0 deletions compiler/src/dmd/frontend.h
Original file line number Diff line number Diff line change
Expand Up @@ -8407,6 +8407,8 @@ struct Id final
static Identifier* dollar;
static Identifier* ctfe;
static Identifier* offset;
static Identifier* bitoffsetof;
static Identifier* bitwidth;
static Identifier* ModuleInfo;
static Identifier* ClassInfo;
static Identifier* classinfo;
Expand Down Expand Up @@ -8698,6 +8700,7 @@ struct Id final
static Identifier* isAbstractClass;
static Identifier* isArithmetic;
static Identifier* isAssociativeArray;
static Identifier* isBitfield;
static Identifier* isFinalClass;
static Identifier* isTemplate;
static Identifier* isPOD;
Expand Down
3 changes: 3 additions & 0 deletions compiler/src/dmd/id.d
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ immutable Msgtable[] msgtable =
{ "ctfe", "__ctfe" },
{ "offset" },
{ "offsetof" },
{ "bitoffsetof" },
{ "bitwidth" },
{ "ModuleInfo" },
{ "ClassInfo" },
{ "classinfo" },
Expand Down Expand Up @@ -455,6 +457,7 @@ immutable Msgtable[] msgtable =
{ "isAbstractClass" },
{ "isArithmetic" },
{ "isAssociativeArray" },
{ "isBitfield" },
{ "isFinalClass" },
{ "isTemplate" },
{ "isPOD" },
Expand Down
11 changes: 11 additions & 0 deletions compiler/src/dmd/traits.d
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,17 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
sm => sm.isTemplateDeclaration() !is null) != 0;
});
}
if (e.ident == Id.isBitfield)
{
if (dim != 1)
return dimError(1);

return isDsymX((s)
{
s = s.toAlias();
return s.isBitFieldDeclaration() !is null;
});
}
if (e.ident == Id.isPOD)
{
if (dim != 1)
Expand Down
21 changes: 19 additions & 2 deletions compiler/src/dmd/typesem.d
Original file line number Diff line number Diff line change
Expand Up @@ -4083,7 +4083,9 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
}
if (v)
{
if (ident == Id.offsetof)
if (ident == Id.offsetof ||
ident == Id.bitoffsetof ||
ident == Id.bitwidth)
{
v.dsymbolSemantic(null);
if (v.isField())
Expand All @@ -4093,7 +4095,20 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
ad.size(e.loc);
if (ad.sizeok != Sizeok.done)
return ErrorExp.get();
return new IntegerExp(e.loc, v.offset, Type.tsize_t);
uint value;
if (ident == Id.offsetof)
value = v.offset;
else // Id.bitoffsetof || Id.bitwidth
{
auto bf = v.isBitFieldDeclaration();
if (bf)
{
value = ident == Id.bitoffsetof ? bf.bitOffset : bf.fieldWidth;
}
else
error(v.loc, "`%s` is not a bitfield, cannot apply `%s`", v.toChars(), ident.toChars());
}
return new IntegerExp(e.loc, value, Type.tsize_t);
}
}
else if (ident == Id._init)
Expand Down Expand Up @@ -4512,6 +4527,8 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
ident != Id._mangleof &&
ident != Id.stringof &&
ident != Id.offsetof &&
ident != Id.bitoffsetof &&
ident != Id.bitwidth &&
// https://issues.dlang.org/show_bug.cgi?id=15045
// Don't forward special built-in member functions.
ident != Id.ctor &&
Expand Down
38 changes: 38 additions & 0 deletions compiler/test/fail_compilation/bitintro.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/* REQUIRED_ARGS: -preview=bitfields
*/

struct S
{
int a;
int b:5, c:6;
}

static if (0)
{
pragma(msg, __traits(isBitfield, S.a));
pragma(msg, __traits(isBitfield, S.b));
pragma(msg, S.b.bitoffsetof);
pragma(msg, S.b.bitwidth);
pragma(msg, S.c.bitoffsetof);
pragma(msg, S.c.bitwidth);
pragma(msg, S.a.bitoffsetof);
pragma(msg, S.a.bitwidth);
}

static assert(__traits(isBitfield, S.a) == false);
static assert(__traits(isBitfield, S.b) == true);
static assert(S.b.bitoffsetof == 0);
static assert(S.b.bitwidth == 5);
static assert(S.c.bitoffsetof == 5);
static assert(S.c.bitwidth == 6);

/* TEST_OUTPUT:
---
fail_compilation/bitintro.d(6): Error: `a` is not a bitfield, cannot apply `bitoffsetof`
fail_compilation/bitintro.d(37): while evaluating: `static assert(a.bitoffsetof)`
fail_compilation/bitintro.d(6): Error: `a` is not a bitfield, cannot apply `bitwidth`
fail_compilation/bitintro.d(38): while evaluating: `static assert(a.bitwidth)`
---
*/
static assert(S.a.bitoffsetof);
static assert(S.a.bitwidth);