Skip to content

Commit

Permalink
Merge pull request #13027 from WalterBright/bitfieldsPosix
Browse files Browse the repository at this point in the history
Bitfields posix
  • Loading branch information
maxhaton committed Aug 29, 2021
2 parents b838466 + 6ec9f4c commit 1334982
Show file tree
Hide file tree
Showing 11 changed files with 441 additions and 51 deletions.
24 changes: 12 additions & 12 deletions src/dmd/cparse.d
Original file line number Diff line number Diff line change
Expand Up @@ -3037,14 +3037,12 @@ final class CParser(AST) : Parser!AST
check(TOK.rightCurly);

if ((*members).length == 0) // C11 6.7.2.1-8
/* TODO: not strict enough, should really be contains "no named members",
* not just "no members".
* I.e. an unnamed bit field, _Static_assert, etc, are not named members,
* but will pass this check.
* Be careful to detect named members that come anonymous structs.
* Correctly doing this will likely mean moving it to typesem.d.
{
/* allow empty structs as an extension
* struct-declarator-list:
* struct-declarator (opt)
*/
error("empty struct-declaration-list for `%s %s`", Token.toChars(structOrUnion), tag ? tag.toChars() : "Anonymous".ptr);
}
}
else if (!tag)
error("missing tag `identifier` after `%s`", Token.toChars(structOrUnion));
Expand Down Expand Up @@ -3139,12 +3137,14 @@ final class CParser(AST) : Parser!AST
dt = tspec;
}
else
dt = cparseDeclarator(DTR.xdirect, tspec, id);
if (!dt)
{
panic();
nextToken();
break; // error recovery
dt = cparseDeclarator(DTR.xdirect, tspec, id);
if (!dt)
{
panic();
nextToken();
break; // error recovery
}
}

AST.Expression width;
Expand Down
117 changes: 91 additions & 26 deletions src/dmd/declaration.d
Original file line number Diff line number Diff line change
Expand Up @@ -1192,14 +1192,7 @@ extern (C++) class VarDeclaration : Declaration
/* If coming after a bit field in progress,
* advance past the field
*/
if (fieldState.inFlight)
{
fieldState.inFlight = false;
if (0 && target.os & Target.OS.Posix)
fieldState.offset += (fieldState.bitOffset + 7) / 8;
else if (0 &&target.os == Target.OS.Windows)
fieldState.offset += fieldState.fieldSize;
}
fieldState.inFlight = false;

const sz = t.size(loc);
assert(sz != SIZE_INVALID && sz < uint.max);
Expand Down Expand Up @@ -1743,13 +1736,23 @@ extern (C++) class BitFieldDeclaration : VarDeclaration

override final void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
{
//printf("BitFieldDeclaration::setFieldOffset(ad = %s) %s\n", ad.toChars(), toChars());
//printf("BitFieldDeclaration::setFieldOffset(ad: %s, field: %s)\n", ad.toChars(), toChars());
static void print(const ref FieldState fieldState)
{
printf("FieldState.offset = %d bytes\n", fieldState.offset);
printf(" .fieldOffset = %d bytes\n", fieldState.fieldOffset);
printf(" .bitOffset = %d bits\n", fieldState.bitOffset);
printf(" .fieldSize = %d bytes\n", fieldState.fieldSize);
printf(" .inFlight = %d\n\n", fieldState.inFlight);
}
//print(fieldState);

Type t = type.toBasetype();
const bool anon = isAnonymous();

// List in ad.fields. Even if the type is error, it's necessary to avoid
// pointless error diagnostic "more initializers than fields" on struct literal.
if (!isAnonymous())
if (!anon)
ad.fields.push(this);

if (t.ty == Terror)
Expand All @@ -1760,17 +1763,34 @@ extern (C++) class BitFieldDeclaration : VarDeclaration
uint memsize = cast(uint)sz; // size of member
uint memalignsize = target.fieldalign(t); // size of member for alignment purposes

if (fieldWidth == 0 && !isAnonymous())
if (fieldWidth == 0 && !anon)
error(loc, "named bit fields cannot have 0 width");
if (fieldWidth > memsize * 8)
error(loc, "bit field width %d is larger than type", fieldWidth);

void startNewField()
{
uint alignsize;
if (target.c.bitFieldStyle == TargetC.BitFieldStyle.Gcc_Clang)
{
if (fieldWidth > 32)
alignsize = memalignsize;
else if (fieldWidth > 16)
alignsize = 4;
else if (fieldWidth > 8)
alignsize = 2;
else
alignsize = 1;
}
else
alignsize = memalignsize;

uint dummy;
offset = AggregateDeclaration.placeField(
&fieldState.offset,
memsize, memalignsize, alignment,
&ad.structsize, &ad.alignsize,
memsize, alignsize, alignment,
&ad.structsize,
anon ? &dummy : &ad.alignsize,
isunion);

fieldState.inFlight = true;
Expand All @@ -1779,42 +1799,87 @@ extern (C++) class BitFieldDeclaration : VarDeclaration
fieldState.fieldSize = memsize;
}

if (!fieldState.inFlight || fieldWidth == 0)
if (target.c.bitFieldStyle == TargetC.BitFieldStyle.Gcc_Clang)
{
startNewField();
if (fieldWidth == 0)
{
if (!isunion)
{
// Use type of zero width field to align to next field
fieldState.offset = (fieldState.offset + memalignsize - 1) & ~(memalignsize - 1);
ad.structsize = fieldState.offset;
}

fieldState.inFlight = false;
return;
}

if (ad.alignsize == 0)
ad.alignsize = 1;
if (!anon &&
ad.alignsize < memalignsize)
ad.alignsize = memalignsize;
}

if (0 && target.os & Target.OS.Posix)
if (fieldWidth == 0)
{
if ((fieldState.offset%4 * 8) + fieldState.bitOffset + fieldWidth > int.sizeof * 8)
fieldState.inFlight = false;
return;
}
else if (!fieldState.inFlight)
{
startNewField();
}
else if (target.c.bitFieldStyle == TargetC.BitFieldStyle.Gcc_Clang)
{
if (fieldState.bitOffset + fieldWidth > memsize * 8)
{
//printf("start1 fieldState.bitOffset:%u fieldWidth:%u memsize:%u\n", fieldState.bitOffset, fieldWidth, memsize);
startNewField();
}
else
{
// if alignment boundary is crossed
uint start = fieldState.fieldOffset * 8 + fieldState.bitOffset;
uint end = start + fieldWidth;
//printf("%s start: %d end: %d memalignsize: %d\n", ad.toChars(), start, end, memalignsize);
if (start / (memalignsize * 8) != (end - 1) / (memalignsize * 8))
{
//printf("alignment is crossed\n");
startNewField();
}
}
}
else if (1 || target.os == Target.OS.Windows)
else if (target.c.bitFieldStyle == TargetC.BitFieldStyle.Dm_Ms)
{
if (memsize != fieldState.fieldSize ||
fieldState.bitOffset + fieldWidth > fieldState.fieldSize * 8)
{
startNewField();
}
}
else
assert(0);

offset = fieldState.fieldOffset;
bitOffset = fieldState.bitOffset;
if (0 && target.os & Target.OS.Posix)

const pastField = bitOffset + fieldWidth;
if (target.c.bitFieldStyle == TargetC.BitFieldStyle.Gcc_Clang)
{
while (bitOffset > memsize * 8)
{
bitOffset -= 8;
offset += 1;
}
auto size = (pastField + 7) / 8;
fieldState.fieldSize = size;
//printf(" offset: %d, size: %d\n", offset, size);
ad.structsize = offset + size;
}
else
fieldState.fieldSize = memsize;
//printf("at end: ad.structsize = %d\n", cast(int)ad.structsize);
//print(fieldState);

//fieldState.fieldSize = memsize;
if (!isunion)
{
fieldState.bitOffset += fieldWidth;
fieldState.bitOffset = pastField;
}

//printf("\t%s: memalignsize = %d\n", toChars(), memalignsize);
Expand Down
8 changes: 5 additions & 3 deletions src/dmd/dsymbol.d
Original file line number Diff line number Diff line change
Expand Up @@ -225,11 +225,13 @@ enum : int
*/
struct FieldState
{
uint offset; /// offset for next field
uint offset; /// byte offset for next field

uint fieldOffset; /// offset for the start of the bit field
uint fieldOffset; /// byte offset for the start of the bit field
uint fieldSize; /// byte size of field
uint fieldAlign; /// byte alignment of field
uint bitOffset; /// bit offset for field
uint fieldSize; /// size of field in bytes

bool inFlight; /// bit field is in flight
}

Expand Down
4 changes: 3 additions & 1 deletion src/dmd/dsymbol.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,10 @@ struct FieldState
unsigned offset;

unsigned fieldOffset;
unsigned fieldSize;
unsigned fieldAlign;
unsigned bitOffset;
unsigned fieldSice;

bool inFlight;
};

Expand Down
11 changes: 7 additions & 4 deletions src/dmd/frontend.h
Original file line number Diff line number Diff line change
Expand Up @@ -2483,22 +2483,25 @@ struct FieldState final
{
uint32_t offset;
uint32_t fieldOffset;
uint32_t bitOffset;
uint32_t fieldSize;
uint32_t fieldAlign;
uint32_t bitOffset;
bool inFlight;
FieldState() :
offset(),
fieldOffset(),
bitOffset(),
fieldSize(),
fieldAlign(),
bitOffset(),
inFlight()
{
}
FieldState(uint32_t offset, uint32_t fieldOffset = 0u, uint32_t bitOffset = 0u, uint32_t fieldSize = 0u, bool inFlight = false) :
FieldState(uint32_t offset, uint32_t fieldOffset = 0u, uint32_t fieldSize = 0u, uint32_t fieldAlign = 0u, uint32_t bitOffset = 0u, bool inFlight = false) :
offset(offset),
fieldOffset(fieldOffset),
bitOffset(bitOffset),
fieldSize(fieldSize),
fieldAlign(fieldAlign),
bitOffset(bitOffset),
inFlight(inFlight)
{}
};
Expand Down
8 changes: 7 additions & 1 deletion src/dmd/todt.d
Original file line number Diff line number Diff line change
Expand Up @@ -900,7 +900,13 @@ private void membersToDt(AggregateDeclaration ad, ref DtBuilder dtb,
finishInFlightBitField();
}
// This relies on all bit fields in the same storage location have the same type
bitFieldSize = cast(uint)vd.type.size();
if (bf)
{
if (target.c.bitFieldStyle == TargetC.BitFieldStyle.Gcc_Clang)
bitFieldSize = (bitOffset + bf.fieldWidth + 7) / 8;
else
bitFieldSize = cast(uint)vd.type.size();
}

assert(offset <= vd.offset);
if (offset < vd.offset)
Expand Down
2 changes: 0 additions & 2 deletions test/compilable/zerosize.d
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,3 @@ extern (C++) struct T { }

static assert(T.sizeof == 1);
static assert(T.alignof == 1);


7 changes: 6 additions & 1 deletion test/fail_compilation/bitfields1.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
/* TEST_OUTPUT:
---
fail_compilation/bitfields1.c(103): Error: no alignment-specifier for bit field declaration
fail_compilation/bitfields1.c(109): Error: empty struct-declaration-list for `struct T`
fail_compilation/bitfields1.c(108): Error: specifier-qualifier-list required
fail_compilation/bitfields1.c(111): Error: specifier-qualifier-list required
fail_compilation/bitfields1.c(112): Error: specifier-qualifier-list required
---
*/

Expand All @@ -17,3 +19,6 @@ struct T
:3;
};

struct E1 { :0; int x; };
struct E2 { int x; :0; };

1 change: 0 additions & 1 deletion test/fail_compilation/failcstuff1.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ fail_compilation/failcstuff1.c(152): Error: `;` or `,` expected
fail_compilation/failcstuff1.c(153): Error: `void` has no value
fail_compilation/failcstuff1.c(153): Error: missing comma
fail_compilation/failcstuff1.c(153): Error: `;` or `,` expected
fail_compilation/failcstuff1.c(154): Error: empty struct-declaration-list for `struct Anonymous`
fail_compilation/failcstuff1.c(157): Error: identifier not allowed in abstract-declarator
fail_compilation/failcstuff1.c(203): Error: storage class not allowed in specifier-qualified-list
fail_compilation/failcstuff1.c(204): Error: storage class not allowed in specifier-qualified-list
Expand Down

0 comments on commit 1334982

Please sign in to comment.