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
21 changes: 21 additions & 0 deletions changelog/bitfields.dd
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
Add bit fields to D

They work just like the bit fields in ImportC do.

https://github.com/dlang/dlang.org/pull/3190

---
struct B
{
int x:3, y:2;
}

static assert(B.sizeof == 4);

int vaporator(B b)
{
b.x = 4;
b.y = 2;
return b.x + b.y; // returns 6
}
---
1 change: 1 addition & 0 deletions src/dmd/cli.d
Original file line number Diff line number Diff line change
Expand Up @@ -843,6 +843,7 @@ dmd -cov -unittest myprog.d
"implement https://github.com/dlang/DIPs/blob/master/DIPs/other/DIP1008.md (@nogc Throwable)"),
Feature("dip1021", "useDIP1021",
"implement https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1021.md (Mutable function arguments)"),
Feature("bitfields", "bitfields", "add bitfields https://github.com/dlang/dlang.org/pull/3190"),
Feature("fieldwise", "fieldwise", "use fieldwise comparisons for struct equality"),
Feature("fixAliasThis", "fixAliasThis",
"when a symbol is resolved, check alias this scope before going to upper scopes"),
Expand Down
26 changes: 26 additions & 0 deletions src/dmd/declaration.d
Original file line number Diff line number Diff line change
Expand Up @@ -1691,6 +1691,32 @@ extern (C++) class BitFieldDeclaration : VarDeclaration
v.visit(this);
}

/***********************************
* Retrieve the .min or .max values.
* Only valid after semantic analysis.
* Params:
* id = Id.min or Id.max
* Returns:
* the min or max value
*/
final ulong getMinMax(Identifier id)
{
const width = fieldWidth;
const uns = type.isunsigned();
const min = id == Id.min;
ulong v;
assert(width != 0); // should have been rejected in semantic pass
if (width == ulong.sizeof * 8)
v = uns ? (min ? ulong.min : ulong.max)
: (min ? long.min : long.max);
else
v = uns ? (min ? 0
: (1L << width) - 1)
: (min ? -(1L << (width - 1))
: (1L << (width - 1)) - 1);
return v;
}

override final void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
{
//printf("BitFieldDeclaration::setFieldOffset(ad: %s, field: %s)\n", ad.toChars(), toChars());
Expand Down
5 changes: 5 additions & 0 deletions src/dmd/dsymbolsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -1204,6 +1204,11 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
if (dsym.errors)
return;

if (!dsym.parent.isStructDeclaration() && !dsym.parent.isClassDeclaration())
{
dsym.error("bit-field must be member of struct, union, or class");
}

sc = sc.startCTFE();
auto width = dsym.width.expressionSemantic(sc);
sc = sc.endCTFE();
Expand Down
18 changes: 18 additions & 0 deletions src/dmd/expressionsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -12605,6 +12605,22 @@ Expression semanticY(DotIdExp exp, Scope* sc, int flag)
Expression e = new IntegerExp(exp.loc, actualAlignment, Type.tsize_t);
return e;
}
else if ((exp.ident == Id.max || exp.ident == Id.min) &&
exp.e1.isVarExp() &&
exp.e1.isVarExp().var.isBitFieldDeclaration())
{
// For `x.max` and `x.min` get the max/min of the bitfield, not the max/min of its type
auto bf = exp.e1.isVarExp().var.isBitFieldDeclaration();
return new IntegerExp(exp.loc, bf.getMinMax(exp.ident), bf.type);
}
else if ((exp.ident == Id.max || exp.ident == Id.min) &&
exp.e1.isDotVarExp() &&
exp.e1.isDotVarExp().var.isBitFieldDeclaration())
{
// For `x.max` and `x.min` get the max/min of the bitfield, not the max/min of its type
auto bf = exp.e1.isDotVarExp().var.isBitFieldDeclaration();
return new IntegerExp(exp.loc, bf.getMinMax(exp.ident), bf.type);
}
else if (cfile && exp.ident == Id.__sizeof && exp.e1.isStringExp())
{
// Sizeof string literal includes the terminating 0
Expand All @@ -12618,7 +12634,9 @@ Expression semanticY(DotIdExp exp, Scope* sc, int flag)
flag = 0;
Expression e = exp.e1.type.dotExp(sc, exp.e1, exp.ident, flag | (exp.noderef ? DotExpFlag.noDeref : 0));
if (e)
{
e = e.expressionSemantic(sc);
}
return e;
}
}
Expand Down
6 changes: 5 additions & 1 deletion src/dmd/frontend.h
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,7 @@ struct Param final
bool ehnogc;
FeatureState dtorFields;
bool fieldwise;
bool bitfields;
FeatureState rvalueRefParam;
CppStdRevision cplusplus;
bool markdown;
Expand Down Expand Up @@ -632,6 +633,7 @@ struct Param final
inclusiveInContracts(),
ehnogc(),
fieldwise(),
bitfields(),
cplusplus((CppStdRevision)201103u),
markdown(true),
vmarkdown(),
Expand Down Expand Up @@ -705,7 +707,7 @@ struct Param final
mapfile()
{
}
Param(bool obj, bool link = true, bool dll = false, bool lib = false, bool multiobj = false, bool oneobj = false, bool trace = false, bool tracegc = false, bool verbose = false, bool vcg_ast = false, bool showColumns = false, bool vtls = false, bool vtemplates = false, bool vtemplatesListInstances = false, bool vgc = false, bool vfield = false, bool vcomplex = true, bool vin = false, uint8_t symdebug = 0u, bool symdebugref = false, bool optimize = false, DiagnosticReporting useDeprecated = (DiagnosticReporting)1u, bool stackstomp = false, bool useUnitTests = false, bool useInline = false, FeatureState useDIP25 = (FeatureState)-1, FeatureState useDIP1000 = (FeatureState)-1, bool useDIP1021 = false, bool release = false, bool preservePaths = false, DiagnosticReporting warnings = (DiagnosticReporting)2u, PIC pic = (PIC)0u, bool color = false, bool cov = false, uint8_t covPercent = 0u, bool ctfe_cov = false, bool nofloat = false, bool ignoreUnsupportedPragmas = false, bool useModuleInfo = true, bool useTypeInfo = true, bool useExceptions = true, bool noSharedAccess = false, bool previewIn = false, bool shortenedMethods = false, bool betterC = false, bool addMain = false, bool allInst = false, bool fix16997 = true, bool fixAliasThis = false, bool inclusiveInContracts = false, bool ehnogc = false, FeatureState dtorFields = (FeatureState)-1, bool fieldwise = false, FeatureState rvalueRefParam = (FeatureState)-1, CppStdRevision cplusplus = (CppStdRevision)201103u, bool markdown = true, bool vmarkdown = false, bool showGaggedErrors = false, bool printErrorContext = false, bool manual = false, bool usage = false, bool mcpuUsage = false, bool transitionUsage = false, bool checkUsage = false, bool checkActionUsage = false, bool revertUsage = false, bool previewUsage = false, bool externStdUsage = false, bool hcUsage = false, bool logo = false, CHECKENABLE useInvariants = (CHECKENABLE)0u, CHECKENABLE useIn = (CHECKENABLE)0u, CHECKENABLE useOut = (CHECKENABLE)0u, CHECKENABLE useArrayBounds = (CHECKENABLE)0u, CHECKENABLE useAssert = (CHECKENABLE)0u, CHECKENABLE useSwitchError = (CHECKENABLE)0u, CHECKENABLE boundscheck = (CHECKENABLE)0u, CHECKACTION checkAction = (CHECKACTION)0u, uint32_t errorLimit = 20u, _d_dynamicArray< const char > argv0 = {}, Array<const char* > modFileAliasStrings = Array<const char* >(), Array<const char* >* imppath = nullptr, Array<const char* >* fileImppath = nullptr, _d_dynamicArray< const char > objdir = {}, _d_dynamicArray< const char > objname = {}, _d_dynamicArray< const char > libname = {}, bool doDocComments = false, _d_dynamicArray< const char > docdir = {}, _d_dynamicArray< const char > docname = {}, Array<const char* > ddocfiles = Array<const char* >(), bool doHdrGeneration = false, _d_dynamicArray< const char > hdrdir = {}, _d_dynamicArray< const char > hdrname = {}, bool hdrStripPlainFunctions = true, CxxHeaderMode doCxxHdrGeneration = (CxxHeaderMode)0u, _d_dynamicArray< const char > cxxhdrdir = {}, _d_dynamicArray< const char > cxxhdrname = {}, bool doJsonGeneration = false, _d_dynamicArray< const char > jsonfilename = {}, JsonFieldFlags jsonFieldFlags = (JsonFieldFlags)0u, OutBuffer* mixinOut = nullptr, const char* mixinFile = nullptr, int32_t mixinLines = 0, uint32_t debuglevel = 0u, Array<const char* >* debugids = nullptr, uint32_t versionlevel = 0u, Array<const char* >* versionids = nullptr, _d_dynamicArray< const char > defaultlibname = {}, _d_dynamicArray< const char > debuglibname = {}, _d_dynamicArray< const char > mscrtlib = {}, _d_dynamicArray< const char > moduleDepsFile = {}, OutBuffer* moduleDeps = nullptr, bool emitMakeDeps = false, _d_dynamicArray< const char > makeDepsFile = {}, Array<const char* > makeDeps = Array<const char* >(), MessageStyle messageStyle = (MessageStyle)0u, bool run = false, Array<const char* > runargs = Array<const char* >(), Array<const char* > objfiles = Array<const char* >(), Array<const char* > linkswitches = Array<const char* >(), Array<bool > linkswitchIsForCC = Array<bool >(), Array<const char* > libfiles = Array<const char* >(), Array<const char* > dllfiles = Array<const char* >(), _d_dynamicArray< const char > deffile = {}, _d_dynamicArray< const char > resfile = {}, _d_dynamicArray< const char > exefile = {}, _d_dynamicArray< const char > mapfile = {}) :
Param(bool obj, bool link = true, bool dll = false, bool lib = false, bool multiobj = false, bool oneobj = false, bool trace = false, bool tracegc = false, bool verbose = false, bool vcg_ast = false, bool showColumns = false, bool vtls = false, bool vtemplates = false, bool vtemplatesListInstances = false, bool vgc = false, bool vfield = false, bool vcomplex = true, bool vin = false, uint8_t symdebug = 0u, bool symdebugref = false, bool optimize = false, DiagnosticReporting useDeprecated = (DiagnosticReporting)1u, bool stackstomp = false, bool useUnitTests = false, bool useInline = false, FeatureState useDIP25 = (FeatureState)-1, FeatureState useDIP1000 = (FeatureState)-1, bool useDIP1021 = false, bool release = false, bool preservePaths = false, DiagnosticReporting warnings = (DiagnosticReporting)2u, PIC pic = (PIC)0u, bool color = false, bool cov = false, uint8_t covPercent = 0u, bool ctfe_cov = false, bool nofloat = false, bool ignoreUnsupportedPragmas = false, bool useModuleInfo = true, bool useTypeInfo = true, bool useExceptions = true, bool noSharedAccess = false, bool previewIn = false, bool shortenedMethods = false, bool betterC = false, bool addMain = false, bool allInst = false, bool fix16997 = true, bool fixAliasThis = false, bool inclusiveInContracts = false, bool ehnogc = false, FeatureState dtorFields = (FeatureState)-1, bool fieldwise = false, bool bitfields = false, FeatureState rvalueRefParam = (FeatureState)-1, CppStdRevision cplusplus = (CppStdRevision)201103u, bool markdown = true, bool vmarkdown = false, bool showGaggedErrors = false, bool printErrorContext = false, bool manual = false, bool usage = false, bool mcpuUsage = false, bool transitionUsage = false, bool checkUsage = false, bool checkActionUsage = false, bool revertUsage = false, bool previewUsage = false, bool externStdUsage = false, bool hcUsage = false, bool logo = false, CHECKENABLE useInvariants = (CHECKENABLE)0u, CHECKENABLE useIn = (CHECKENABLE)0u, CHECKENABLE useOut = (CHECKENABLE)0u, CHECKENABLE useArrayBounds = (CHECKENABLE)0u, CHECKENABLE useAssert = (CHECKENABLE)0u, CHECKENABLE useSwitchError = (CHECKENABLE)0u, CHECKENABLE boundscheck = (CHECKENABLE)0u, CHECKACTION checkAction = (CHECKACTION)0u, uint32_t errorLimit = 20u, _d_dynamicArray< const char > argv0 = {}, Array<const char* > modFileAliasStrings = Array<const char* >(), Array<const char* >* imppath = nullptr, Array<const char* >* fileImppath = nullptr, _d_dynamicArray< const char > objdir = {}, _d_dynamicArray< const char > objname = {}, _d_dynamicArray< const char > libname = {}, bool doDocComments = false, _d_dynamicArray< const char > docdir = {}, _d_dynamicArray< const char > docname = {}, Array<const char* > ddocfiles = Array<const char* >(), bool doHdrGeneration = false, _d_dynamicArray< const char > hdrdir = {}, _d_dynamicArray< const char > hdrname = {}, bool hdrStripPlainFunctions = true, CxxHeaderMode doCxxHdrGeneration = (CxxHeaderMode)0u, _d_dynamicArray< const char > cxxhdrdir = {}, _d_dynamicArray< const char > cxxhdrname = {}, bool doJsonGeneration = false, _d_dynamicArray< const char > jsonfilename = {}, JsonFieldFlags jsonFieldFlags = (JsonFieldFlags)0u, OutBuffer* mixinOut = nullptr, const char* mixinFile = nullptr, int32_t mixinLines = 0, uint32_t debuglevel = 0u, Array<const char* >* debugids = nullptr, uint32_t versionlevel = 0u, Array<const char* >* versionids = nullptr, _d_dynamicArray< const char > defaultlibname = {}, _d_dynamicArray< const char > debuglibname = {}, _d_dynamicArray< const char > mscrtlib = {}, _d_dynamicArray< const char > moduleDepsFile = {}, OutBuffer* moduleDeps = nullptr, bool emitMakeDeps = false, _d_dynamicArray< const char > makeDepsFile = {}, Array<const char* > makeDeps = Array<const char* >(), MessageStyle messageStyle = (MessageStyle)0u, bool run = false, Array<const char* > runargs = Array<const char* >(), Array<const char* > objfiles = Array<const char* >(), Array<const char* > linkswitches = Array<const char* >(), Array<bool > linkswitchIsForCC = Array<bool >(), Array<const char* > libfiles = Array<const char* >(), Array<const char* > dllfiles = Array<const char* >(), _d_dynamicArray< const char > deffile = {}, _d_dynamicArray< const char > resfile = {}, _d_dynamicArray< const char > exefile = {}, _d_dynamicArray< const char > mapfile = {}) :
obj(obj),
link(link),
dll(dll),
Expand Down Expand Up @@ -759,6 +761,7 @@ struct Param final
ehnogc(ehnogc),
dtorFields(dtorFields),
fieldwise(fieldwise),
bitfields(bitfields),
rvalueRefParam(rvalueRefParam),
cplusplus(cplusplus),
markdown(markdown),
Expand Down Expand Up @@ -5855,6 +5858,7 @@ class BitFieldDeclaration : public VarDeclaration
BitFieldDeclaration* syntaxCopy(Dsymbol* s);
BitFieldDeclaration* isBitFieldDeclaration();
void accept(Visitor* v);
uint64_t getMinMax(Identifier* id);
void setFieldOffset(AggregateDeclaration* ad, FieldState& fieldState, bool isunion);
};

Expand Down
1 change: 1 addition & 0 deletions src/dmd/globals.d
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ extern (C++) struct Param
FeatureState dtorFields; // destruct fields of partially constructed objects
// https://issues.dlang.org/show_bug.cgi?id=14246
bool fieldwise; // do struct equality testing field-wise rather than by memcmp()
bool bitfields; // support C style bit fields
FeatureState rvalueRefParam; // allow rvalues to be arguments to ref parameters
// https://dconf.org/2019/talks/alexandrescu.html
// https://gist.github.com/andralex/e5405a5d773f07f73196c05f8339435a
Expand Down
1 change: 1 addition & 0 deletions src/dmd/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ struct Param
FeatureState dtorFields; // destruct fields of partially constructed objects
// https://issues.dlang.org/show_bug.cgi?id=14246
bool fieldwise; // do struct equality testing field-wise rather than by memcmp()
bool bitfields; // support C style bit fields
FeatureState rvalueRefParam; // allow rvalues to be arguments to ref parameters
CppStdRevision cplusplus; // version of C++ name mangling to support
bool markdown; // enable Markdown replacements in Ddoc
Expand Down
58 changes: 47 additions & 11 deletions src/dmd/parse.d
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,15 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
return true;
}

/************************************
* Parse declarations and definitions
* Params:
* once = !=0 means parse exactly one decl or def
* pLastDecl = set to last decl or def parsed
* pAttrs = keep track of attributes
* Returns:
* array of declared symbols
*/
AST.Dsymbols* parseDeclDefs(int once, AST.Dsymbol* pLastDecl = null, PrefixAttributes!AST* pAttrs = null)
{
AST.Dsymbol lastDecl = null; // used to link unittest to its previous declaration
Expand Down Expand Up @@ -4298,7 +4307,8 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
* These can be:
* 1. declarations at global/class level
* 2. declarations at statement level
* Return array of Declaration *'s.
* Returns:
* array of Declarations.
*/
private AST.Dsymbols* parseDeclarations(bool autodecl, PrefixAttributes!AST* pAttrs, const(char)* comment)
{
Expand Down Expand Up @@ -4459,6 +4469,12 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
else if (t != tfirst)
error("multiple declarations must have the same type, not `%s` and `%s`", tfirst.toChars(), t.toChars());

if (token.value == TOK.colon && !ident && t.ty != Tfunction)
{
// Unnamed bit field
ident = Identifier.generateAnonymousId("BitField");
}

bool isThis = (t.ty == Tident && (cast(AST.TypeIdentifier)t).ident == Id.This && token.value == TOK.assign);
if (ident)
checkCstyleTypeSyntax(loc, t, alt, ident);
Expand Down Expand Up @@ -4591,19 +4607,39 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
}
else if (ident)
{
AST.Expression width;
if (token.value == TOK.colon)
{
nextToken();
width = parseCondExp();
}

AST.Initializer _init = null;
if (token.value == TOK.assign)
{
nextToken();
_init = parseInitializer();
}

auto v = new AST.VarDeclaration(loc, t, ident, _init);
v.storage_class = storage_class;
if (pAttrs)
pAttrs.storageClass = STC.undefined_;

AST.Dsymbol s = v;
AST.Dsymbol s;
if (width)
{
if (!global.params.bitfields)
error("use -preview=bitfields for bitfield support");
if (_init)
error("initializer not allowed for bit-field declaration");
if (storage_class)
error("storage class not allowed for bit-field declaration");
s = new AST.BitFieldDeclaration(width.loc, t, ident, width);
}
else
{
auto v = new AST.VarDeclaration(loc, t, ident, _init);
v.storage_class = storage_class;
if (pAttrs)
pAttrs.storageClass = STC.undefined_;
s = v;
}

if (tpl && _init)
{
Expand All @@ -4616,7 +4652,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
{
auto ax = new AST.Dsymbols();
ax.push(s);
s = new AST.AlignDeclaration(v.loc, ealign, ax);
s = new AST.AlignDeclaration(s.loc, ealign, ax);
}
if (link != linkage)
{
Expand Down Expand Up @@ -4646,12 +4682,12 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
default:
if (loc.linnum != token.loc.linnum)
{
error("semicolon needed to end declaration of `%s`, instead of `%s`", v.toChars(), token.toChars());
errorSupplemental(loc, "`%s` declared here", v.toChars());
error("semicolon needed to end declaration of `%s`, instead of `%s`", s.toChars(), token.toChars());
errorSupplemental(loc, "`%s` declared here", s.toChars());
}
else
{
error("semicolon needed to end declaration of `%s` instead of `%s`", v.toChars(), token.toChars());
error("semicolon needed to end declaration of `%s` instead of `%s`", s.toChars(), token.toChars());
}
break;
}
Expand Down
Loading