Add a notion of an incomplete struct type

This commit is contained in:
Rui Ueyama 2020-09-20 16:20:35 +09:00
parent 0993b404fc
commit f9a327ae97
4 changed files with 41 additions and 11 deletions

View File

@ -225,6 +225,7 @@ Type *pointer_to(Type *base);
Type *func_type(Type *return_ty);
Type *array_of(Type *base, int size);
Type *enum_type(void);
Type *struct_type(void);
void add_type(Node *node);
//

42
parse.c
View File

@ -1060,22 +1060,36 @@ static Type *struct_union_decl(Token **rest, Token *tok) {
}
if (tag && !equal(tok, "{")) {
TagScope *sc = find_tag(tag);
if (!sc)
error_tok(tag, "unknown struct type");
*rest = tok;
return sc->ty;
TagScope *sc = find_tag(tag);
if (sc)
return sc->ty;
Type *ty = struct_type();
ty->size = -1;
push_tag_scope(tag, ty);
return ty;
}
// Construct a struct object.
Type *ty = calloc(1, sizeof(Type));
ty->kind = TY_STRUCT;
struct_members(rest, tok->next, ty);
ty->align = 1;
tok = skip(tok, "{");
// Construct a struct object.
Type *ty = struct_type();
struct_members(rest, tok, ty);
if (tag) {
// If this is a redefinition, overwrite a previous type.
// Otherwise, register the struct type.
TagScope *sc = find_tag(tag);
if (sc && sc->depth == scope_depth) {
*sc->ty = *ty;
return sc->ty;
}
// Register the struct type if a name was given.
if (tag)
push_tag_scope(tag, ty);
}
return ty;
}
@ -1084,6 +1098,9 @@ static Type *struct_decl(Token **rest, Token *tok) {
Type *ty = struct_union_decl(rest, tok);
ty->kind = TY_STRUCT;
if (ty->size < 0)
return ty;
// Assign offsets within the struct to members.
int offset = 0;
for (Member *mem = ty->members; mem; mem = mem->next) {
@ -1103,6 +1120,9 @@ static Type *union_decl(Token **rest, Token *tok) {
Type *ty = struct_union_decl(rest, tok);
ty->kind = TY_UNION;
if (ty->size < 0)
return ty;
// If union, we don't have to assign offsets because they
// are already initialized to zero. We need to compute the
// alignment and the size though.

View File

@ -52,6 +52,11 @@ int main() {
ASSERT(16, ({ struct {char a; long b;} x; sizeof(x); }));
ASSERT(4, ({ struct {char a; short b;} x; sizeof(x); }));
ASSERT(8, ({ struct foo *bar; sizeof(bar); }));
ASSERT(4, ({ struct T *foo; struct T {int x;}; sizeof(struct T); }));
ASSERT(1, ({ struct T { struct T *next; int x; } a; struct T b; b.x=1; a.next=&b; a.next->x; }));
ASSERT(4, ({ typedef struct T T; struct T { int x; }; sizeof(T); }));
printf("OK\n");
return 0;
}

4
type.c
View File

@ -52,6 +52,10 @@ Type *enum_type(void) {
return new_type(TY_ENUM, 4, 4);
}
Type *struct_type(void) {
return new_type(TY_STRUCT, 0, 1);
}
static Type *get_common_type(Type *ty1, Type *ty2) {
if (ty1->base)
return pointer_to(ty1->base);