From b5049f4ff910f254cdbc146c3095a5b4eb625cb7 Mon Sep 17 00:00:00 2001 From: Walter Bright Date: Sun, 5 May 2024 16:00:32 -0700 Subject: [PATCH] bitfields: add bitoffsetof, bitwidth, isBitfield --- changelog/dmd.bitfield-introspection.dd | 9 ++++++ compiler/src/dmd/expressionsem.d | 8 +++-- compiler/src/dmd/frontend.h | 3 ++ compiler/src/dmd/id.d | 3 ++ compiler/src/dmd/traits.d | 11 +++++++ compiler/src/dmd/typesem.d | 21 +++++++++++-- compiler/test/fail_compilation/bitintro.d | 38 +++++++++++++++++++++++ 7 files changed, 89 insertions(+), 4 deletions(-) create mode 100644 changelog/dmd.bitfield-introspection.dd create mode 100644 compiler/test/fail_compilation/bitintro.d diff --git a/changelog/dmd.bitfield-introspection.dd b/changelog/dmd.bitfield-introspection.dd new file mode 100644 index 000000000000..3c5a3f32a5f9 --- /dev/null +++ b/changelog/dmd.bitfield-introspection.dd @@ -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 diff --git a/compiler/src/dmd/expressionsem.d b/compiler/src/dmd/expressionsem.d index 3502a1cecf79..9b6a45019b2b 100644 --- a/compiler/src/dmd/expressionsem.d +++ b/compiler/src/dmd/expressionsem.d @@ -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); @@ -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) )) diff --git a/compiler/src/dmd/frontend.h b/compiler/src/dmd/frontend.h index a208add26a6f..de2156ffe449 100644 --- a/compiler/src/dmd/frontend.h +++ b/compiler/src/dmd/frontend.h @@ -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; @@ -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; diff --git a/compiler/src/dmd/id.d b/compiler/src/dmd/id.d index 6dbc60b020cc..dfaf8f5200b3 100644 --- a/compiler/src/dmd/id.d +++ b/compiler/src/dmd/id.d @@ -102,6 +102,8 @@ immutable Msgtable[] msgtable = { "ctfe", "__ctfe" }, { "offset" }, { "offsetof" }, + { "bitoffsetof" }, + { "bitwidth" }, { "ModuleInfo" }, { "ClassInfo" }, { "classinfo" }, @@ -455,6 +457,7 @@ immutable Msgtable[] msgtable = { "isAbstractClass" }, { "isArithmetic" }, { "isAssociativeArray" }, + { "isBitfield" }, { "isFinalClass" }, { "isTemplate" }, { "isPOD" }, diff --git a/compiler/src/dmd/traits.d b/compiler/src/dmd/traits.d index 81d42e6e8be5..5ec38449123c 100644 --- a/compiler/src/dmd/traits.d +++ b/compiler/src/dmd/traits.d @@ -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) diff --git a/compiler/src/dmd/typesem.d b/compiler/src/dmd/typesem.d index 195fdc723a21..7643dc59c107 100644 --- a/compiler/src/dmd/typesem.d +++ b/compiler/src/dmd/typesem.d @@ -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()) @@ -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) @@ -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 && diff --git a/compiler/test/fail_compilation/bitintro.d b/compiler/test/fail_compilation/bitintro.d new file mode 100644 index 000000000000..d58c3ea56ff0 --- /dev/null +++ b/compiler/test/fail_compilation/bitintro.d @@ -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);