Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bitfields posix #13027

Merged
merged 3 commits into from
Aug 29, 2021
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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