Fix bugzilla 24594 - ImportC: Packed struct has wrong layout (#16611)

Packed structs were already implemented with the Microsoft syntax
(e.g. `#pragma pack(push, 1)`), but the GCC syntax was ignored.
This commit is contained in:
Tim Schendekehl 2024-06-22 14:48:09 +02:00 committed by GitHub
parent 1917164050
commit 557e1d5eea
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 58 additions and 3 deletions

View file

@ -3634,6 +3634,12 @@ final class CParser(AST) : Parser!AST
* type on the target machine. It's the opposite of __attribute__((packed))
*/
}
else if (token.ident == Id.packed)
{
specifier.packalign.set(1);
specifier.packalign.setPack(true);
nextToken();
}
else if (token.ident == Id.always_inline) // https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html
{
specifier.scw |= SCW.xinline;
@ -3982,7 +3988,7 @@ final class CParser(AST) : Parser!AST
members = new AST.Dsymbols(); // so `members` will be non-null even with 0 members
while (token.value != TOK.rightCurly)
{
cparseStructDeclaration(members);
cparseStructDeclaration(members, packalign);
if (token.value == TOK.endOfFile)
break;
@ -3996,6 +4002,24 @@ final class CParser(AST) : Parser!AST
* struct-declarator (opt)
*/
}
/* GNU Extensions
* Parse the postfix gnu-attributes (opt)
*/
Specifier specifier;
if (token.value == TOK.__attribute__)
cparseGnuAttributes(specifier);
if (!specifier.packalign.isUnknown)
{
packalign.set(specifier.packalign.get());
packalign.setPack(specifier.packalign.isPack());
foreach (ref d; (*members)[])
{
auto decls = new AST.Dsymbols(1);
(*decls)[0] = d;
d = new AST.AlignDeclaration(d.loc, specifier.packalign, decls);
}
}
}
else if (!tag)
error("missing tag `identifier` after `%s`", Token.toChars(structOrUnion));
@ -4027,8 +4051,9 @@ final class CParser(AST) : Parser!AST
* declarator (opt) : constant-expression
* Params:
* members = where to put the fields (members)
* packalign = alignment to use for struct members
*/
void cparseStructDeclaration(AST.Dsymbols* members)
void cparseStructDeclaration(AST.Dsymbols* members, structalign_t packalign)
{
//printf("cparseStructDeclaration()\n");
if (token.value == TOK._Static_assert)
@ -4039,7 +4064,7 @@ final class CParser(AST) : Parser!AST
}
Specifier specifier;
specifier.packalign = this.packalign;
specifier.packalign = packalign.isUnknown ? this.packalign : packalign;
auto tspec = cparseSpecifierQualifierList(LVL.member, specifier);
if (!tspec)
{

View file

@ -8799,6 +8799,7 @@ struct Id final
static Identifier* define;
static Identifier* undef;
static Identifier* ident;
static Identifier* packed;
static void initialize();
Id()
{

View file

@ -574,6 +574,7 @@ immutable Msgtable[] msgtable =
{ "define" },
{ "undef" },
{ "ident" },
{ "packed" },
];

View file

@ -0,0 +1,28 @@
#include <stdint.h>
struct S1
{
uint32_t a;
uint64_t b;
} __attribute__((packed));
_Static_assert(sizeof(S1) == 12, "S1 size");
_Static_assert(&((struct S1*)0)->b == 4, "S1::b offset");
struct __attribute__((packed)) S2
{
uint8_t a;
uint16_t b;
};
_Static_assert(sizeof(S2) == 3, "S2 size");
_Static_assert(&((struct S2*)0)->b == 1, "S2::b offset");
struct __attribute__((packed)) S3
{
uint32_t a;
uint8_t b;
};
_Static_assert(sizeof(S3) == 5, "S3 size");
_Static_assert(&((struct S3*)0)->b == 4, "S3::b offset");