diff --git a/compiler/src/dmd/cparse.d b/compiler/src/dmd/cparse.d index 62882dc0fb..bdff67476d 100644 --- a/compiler/src/dmd/cparse.d +++ b/compiler/src/dmd/cparse.d @@ -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) { diff --git a/compiler/src/dmd/frontend.h b/compiler/src/dmd/frontend.h index a266acd17d..a42c50c1fe 100644 --- a/compiler/src/dmd/frontend.h +++ b/compiler/src/dmd/frontend.h @@ -8799,6 +8799,7 @@ struct Id final static Identifier* define; static Identifier* undef; static Identifier* ident; + static Identifier* packed; static void initialize(); Id() { diff --git a/compiler/src/dmd/id.d b/compiler/src/dmd/id.d index dfaf8f5200..f676361d95 100644 --- a/compiler/src/dmd/id.d +++ b/compiler/src/dmd/id.d @@ -574,6 +574,7 @@ immutable Msgtable[] msgtable = { "define" }, { "undef" }, { "ident" }, + { "packed" }, ]; diff --git a/compiler/test/compilable/test24594.c b/compiler/test/compilable/test24594.c new file mode 100644 index 0000000000..caa85779c2 --- /dev/null +++ b/compiler/test/compilable/test24594.c @@ -0,0 +1,28 @@ +#include + +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");