Add __attribute__((packed))

This commit is contained in:
Rui Ueyama 2020-10-07 11:14:15 +09:00
parent 395308c77b
commit 44bea4c85a
4 changed files with 50 additions and 9 deletions

View File

@ -349,6 +349,7 @@ struct Type {
// Struct // Struct
Member *members; Member *members;
bool is_flexible; bool is_flexible;
bool is_packed;
// Function type // Function type
Type *return_ty; Type *return_ty;

36
parse.c
View File

@ -2595,8 +2595,26 @@ static void struct_members(Token **rest, Token *tok, Type *ty) {
ty->members = head.next; ty->members = head.next;
} }
// struct-union-decl = ident? ("{" struct-members)? // attribute = ("__attribute__" "(" "(" "packed" ")" ")")?
static Token *attribute(Token *tok, Type *ty) {
if (!equal(tok, "__attribute__"))
return tok;
tok = tok->next;
tok = skip(tok, "(");
tok = skip(tok, "(");
tok = skip(tok, "packed");
tok = skip(tok, ")");
tok = skip(tok, ")");
ty->is_packed = true;
return tok;
}
// struct-union-decl = attribute? ident? ("{" struct-members)?
static Type *struct_union_decl(Token **rest, Token *tok) { static Type *struct_union_decl(Token **rest, Token *tok) {
Type *ty = struct_type();
tok = attribute(tok, ty);
// Read a tag. // Read a tag.
Token *tag = NULL; Token *tag = NULL;
if (tok->kind == TK_IDENT) { if (tok->kind == TK_IDENT) {
@ -2607,11 +2625,10 @@ static Type *struct_union_decl(Token **rest, Token *tok) {
if (tag && !equal(tok, "{")) { if (tag && !equal(tok, "{")) {
*rest = tok; *rest = tok;
Type *ty = find_tag(tag); Type *ty2 = find_tag(tag);
if (ty) if (ty2)
return ty; return ty2;
ty = struct_type();
ty->size = -1; ty->size = -1;
push_tag_scope(tag, ty); push_tag_scope(tag, ty);
return ty; return ty;
@ -2620,8 +2637,8 @@ static Type *struct_union_decl(Token **rest, Token *tok) {
tok = skip(tok, "{"); tok = skip(tok, "{");
// Construct a struct object. // Construct a struct object.
Type *ty = struct_type(); struct_members(&tok, tok, ty);
struct_members(rest, tok, ty); *rest = attribute(tok, ty);
if (tag) { if (tag) {
// If this is a redefinition, overwrite a previous type. // If this is a redefinition, overwrite a previous type.
@ -2663,12 +2680,13 @@ static Type *struct_decl(Token **rest, Token *tok) {
mem->bit_offset = bits % (sz * 8); mem->bit_offset = bits % (sz * 8);
bits += mem->bit_width; bits += mem->bit_width;
} else { } else {
bits = align_to(bits, mem->align * 8); if (!ty->is_packed)
bits = align_to(bits, mem->align * 8);
mem->offset = bits / 8; mem->offset = bits / 8;
bits += mem->ty->size * 8; bits += mem->ty->size * 8;
} }
if (ty->align < mem->align) if (!ty->is_packed && ty->align < mem->align)
ty->align = mem->align; ty->align = mem->align;
} }

21
test/attribute.c Normal file
View File

@ -0,0 +1,21 @@
#include "test.h"
#include "stddef.h"
int main() {
ASSERT(5, ({ struct { char a; int b; } __attribute__((packed)) x; sizeof(x); }));
ASSERT(0, offsetof(struct __attribute__((packed)) { char a; int b; }, a));
ASSERT(1, offsetof(struct __attribute__((packed)) { char a; int b; }, b));
ASSERT(5, ({ struct __attribute__((packed)) { char a; int b; } x; sizeof(x); }));
ASSERT(0, offsetof(struct { char a; int b; } __attribute__((packed)), a));
ASSERT(1, offsetof(struct { char a; int b; } __attribute__((packed)), b));
ASSERT(9, ({ typedef struct { char a; int b[2]; } __attribute__((packed)) T; sizeof(T); }));
ASSERT(9, ({ typedef struct __attribute__((packed)) { char a; int b[2]; } T; sizeof(T); }));
ASSERT(1, offsetof(struct __attribute__((packed)) T { char a; int b[2]; }, b));
ASSERT(1, _Alignof(struct __attribute__((packed)) { char a; int b[2]; }));
printf("OK\n");
return 0;
}

View File

@ -167,6 +167,7 @@ static bool is_keyword(Token *tok) {
"unsigned", "const", "volatile", "auto", "register", "restrict", "unsigned", "const", "volatile", "auto", "register", "restrict",
"__restrict", "__restrict__", "_Noreturn", "float", "double", "__restrict", "__restrict__", "_Noreturn", "float", "double",
"typeof", "asm", "_Thread_local", "__thread", "_Atomic", "typeof", "asm", "_Thread_local", "__thread", "_Atomic",
"__attribute__",
}; };
for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++) for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++)