cproc

Unnamed repository; edit this file 'description' to name the repository.
git clone git://git.nihaljere.xyz/cproc
Log | Files | Refs | Submodules | README | LICENSE

commit 8ffedb1f24804c9c13121a12b3802610f2b6f9df
parent e477588215b222bf42d72385d9808db56e0bfce0
Author: Michael Forney <mforney@mforney.org>
Date:   Fri, 15 Feb 2019 01:39:53 -0800

Don't embed anonymous struct members into parent

While this works nicely for structs, when unions are involved it
makes it impossible to find the next member to initialize without keeping
track of extra data per member.

Diffstat:
Mdecl.c | 74++++++++++++++++++++++++++++++++++++++++----------------------------------
Mexpr.c | 16+++++++++-------
Minit.c | 80++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
Mqbe.c | 2+-
Mtype.c | 20+++++++++++++++-----
Mtype.h | 5+++--
6 files changed, 113 insertions(+), 84 deletions(-)

diff --git a/decl.c b/decl.c @@ -147,7 +147,7 @@ funcspec(enum funcspecifier *fs) return 1; } -static void structdecl(struct scope *, struct type *); +static void structdecl(struct scope *, struct type *, struct member ***); static struct type * tagspec(struct scope *s) @@ -156,6 +156,7 @@ tagspec(struct scope *s) char *tag; enum typekind kind; struct declaration *d; + struct member **end; uint64_t i; switch (tok.kind) { @@ -189,7 +190,7 @@ tagspec(struct scope *s) t->size = 0; t->align = 0; t->structunion.tag = tag; - t->structunion.members = (struct array){0}; + t->structunion.members = NULL; } t->incomplete = true; if (tag) @@ -203,8 +204,9 @@ tagspec(struct scope *s) switch (t->kind) { case TYPESTRUCT: case TYPEUNION: + end = &t->structunion.members; while (tok.kind != TRBRACE) - structdecl(s, t); + structdecl(s, t, &end); next(); t->size = ALIGNUP(t->size, t->align); t->incomplete = false; @@ -621,51 +623,55 @@ paramdecl(struct scope *s, struct parameter *params) return true; } -// XXX: cleanup static void -structdecl(struct scope *s, struct type *t) +addmember(struct type *t, struct member ***end, struct type *mt, char *name, int align) { - struct type *base; struct member *m; - int basealign, align; - base = declspecs(s, NULL, NULL, &basealign); + m = xmalloc(sizeof(*m)); + m->type = mt; + m->name = name; + m->next = NULL; + **end = m; + *end = &m->next; + + assert(mt->align > 0); + if (align < mt->align) + align = mt->align; + t->size = ALIGNUP(t->size, align); + if (t->kind == TYPESTRUCT) { + m->offset = t->size; + t->size += mt->size; + } else { + m->offset = 0; + if (t->size < mt->size) + t->size = mt->size; + } + if (t->align < align) + t->align = align; +} + +static void +structdecl(struct scope *s, struct type *t, struct member ***end) +{ + struct type *base, *mt; + char *name; + int align; + + base = declspecs(s, NULL, NULL, &align); if (!base) error(&tok.loc, "no type in struct member declaration"); if (tok.kind == TSEMICOLON) { if ((base->kind != TYPESTRUCT && base->kind != TYPEUNION) || base->structunion.tag) error(&tok.loc, "struct declaration must declare at least one member"); next(); - if (basealign < base->align) - basealign = base->align; - t->size = ALIGNUP(t->size, basealign); - arrayforeach (&base->structunion.members, m) - m->offset += t->size; - arrayaddbuf(&t->structunion.members, base->structunion.members.val, base->structunion.members.len); - t->size += ALIGNUP(base->size, basealign); - if (t->align < basealign) - t->align = basealign; + addmember(t, end, base, NULL, align); return; } for (;;) { - align = basealign; if (tok.kind != TCOLON) { - m = arrayadd(&t->structunion.members, sizeof(*m)); - m->type = declarator(s, base, &m->name, false); - assert(m->type->align > 0); - if (align < m->type->align) - align = m->type->align; - t->size = ALIGNUP(t->size, align); - if (t->kind == TYPESTRUCT) { - m->offset = t->size; - t->size += m->type->size; - } else { - m->offset = 0; - if (t->size < m->type->size) - t->size = m->type->size; - } - if (t->align < align) - t->align = align; + mt = declarator(s, base, &name, false); + addmember(t, end, mt, name, align); } if (tok.kind == TCOLON) error(&tok.loc, "bit-fields are not yet supported"); diff --git a/expr.c b/expr.c @@ -373,6 +373,7 @@ postfixexpr(struct scope *s, struct expression *r) struct parameter *p; struct member *m; char *name; + uint64_t offset; enum tokenkind op; bool lvalue; @@ -434,10 +435,10 @@ postfixexpr(struct scope *s, struct expression *r) name = expect(TIDENT, "after ','"); if (t->kind != TYPESTRUCT && t->kind != TYPEUNION) error(&tok.loc, "type is not a struct/union type"); - m = typemember(t, name); - if (!m) + offset = 0; + if (!typemember(t, name, &offset)) error(&tok.loc, "struct/union has no member named '%s'", name); - e = mkconstexpr(&typeulong, m->offset); + e = mkconstexpr(&typeulong, offset); free(name); expect(TRPAREN, "after member name"); } else { @@ -497,11 +498,12 @@ postfixexpr(struct scope *s, struct expression *r) error(&tok.loc, "expected identifier after '->' operator"); lvalue = op == TARROW || r->unary.base->flags & EXPRFLAG_LVAL; r = exprconvert(r, mkpointertype(&typechar)); - m = typemember(t, tok.lit); - if (!m) + offset = 0; + t = typemember(t, tok.lit, &offset); + if (!t) error(&tok.loc, "struct/union has no member named '%s'", tok.lit); - r = mkbinaryexpr(&tok.loc, TADD, r, mkconstexpr(&typeulong, m->offset)); - r = exprconvert(r, mkpointertype(mkqualifiedtype(m->type, tq))); + r = mkbinaryexpr(&tok.loc, TADD, r, mkconstexpr(&typeulong, offset)); + r = exprconvert(r, mkpointertype(mkqualifiedtype(t, tq))); e = mkexpr(EXPRUNARY, r->type->base, lvalue ? EXPRFLAG_LVAL : 0); e->unary.op = TMUL; e->unary.base = r; diff --git a/init.c b/init.c @@ -3,7 +3,6 @@ #include <inttypes.h> #include <stdbool.h> #include <stdint.h> -#include <stdio.h> #include <stdlib.h> #include <string.h> #include "util.h" @@ -84,16 +83,48 @@ updatearray(struct type *t, uint64_t i) } static void +subobj(struct initparser *p, struct type *t, uint64_t off) +{ + off += p->sub->offset; + if (++p->sub == p->obj + LEN(p->obj)) + fatal("internal error: too many designators"); + p->sub->type = t; + p->sub->offset = off; + p->sub->iscur = false; +} + +static bool +findmember(struct initparser *p, char *name) +{ + struct member *m; + + for (m = p->sub->type->structunion.members; m; m = m->next) { + if (m->name) { + if (strcmp(m->name, name) == 0) { + p->sub->mem = m; + subobj(p, m->type, m->offset); + return true; + } + } else { + subobj(p, m->type, m->offset); + if (findmember(p, name)) + return true; + --p->sub; + } + } + return false; +} + +static void designator(struct scope *s, struct initparser *p) { struct type *t; uint64_t offset; - const char *name; + char *name; p->sub = p->cur; - t = p->sub->type; - offset = p->sub->offset; for (;;) { + t = p->sub->type; switch (tok.kind) { case TLBRACK: if (t->kind != TYPEARRAY) @@ -105,32 +136,21 @@ designator(struct scope *s, struct initparser *p) else if (p->sub->idx >= t->array.length) error(&tok.loc, "index designator is larger than array length"); expect(TRBRACK, "for index designator"); - t = t->base; - offset += p->sub->idx * t->size; + subobj(p, t->base, p->sub->idx * t->base->size); break; case TPERIOD: if (t->kind != TYPESTRUCT && t->kind != TYPEUNION) error(&tok.loc, "member designator only valid for struct/union types"); next(); name = expect(TIDENT, "for member designator"); - arrayforeach (&t->structunion.members, p->sub->mem) { - if (strcmp(p->sub->mem->name, name) == 0) - break; - } - if (!p->sub->mem) + if (!findmember(p, name)) error(&tok.loc, "%s has no member named '%s'", t->kind == TYPEUNION ? "union" : "struct", name); - t = p->sub->mem->type; - offset += p->sub->mem->offset; + free(name); break; default: expect(TASSIGN, "after designator"); return; } - if (++p->sub == p->obj + LEN(p->obj)) - fatal("internal error: too many designators"); - p->sub->type = t; - p->sub->offset = offset; - p->sub->iscur = false; } } @@ -138,9 +158,7 @@ static void focus(struct initparser *p) { struct type *t; - uint64_t offset; - offset = p->sub->offset; switch (p->sub->type->kind) { case TYPEARRAY: p->sub->idx = 0; @@ -150,17 +168,13 @@ focus(struct initparser *p) break; case TYPESTRUCT: case TYPEUNION: - p->sub->mem = p->sub->type->structunion.members.val; + p->sub->mem = p->sub->type->structunion.members; t = p->sub->mem->type; break; default: t = p->sub->type; } - if (++p->sub == p->obj + LEN(p->obj)) - fatal("internal error: too many designators"); - p->sub->type = typeunqual(t, NULL); - p->sub->offset = offset; - p->sub->iscur = false; + subobj(p, typeunqual(t, NULL), 0); } static void @@ -171,7 +185,6 @@ advance(struct initparser *p) for (;;) { --p->sub; - offset = p->sub->offset; switch (p->sub->type->kind) { case TYPEARRAY: ++p->sub->idx; @@ -179,15 +192,15 @@ advance(struct initparser *p) updatearray(p->sub->type, p->sub->idx); if (p->sub->idx < p->sub->type->array.length) { t = p->sub->type->base; - offset += t->size * p->sub->idx; + offset = t->size * p->sub->idx; goto done; } break; case TYPESTRUCT: - ++p->sub->mem; - if (p->sub->mem != (void *)((uintptr_t)p->sub->type->structunion.members.val + p->sub->type->structunion.members.len)) { + p->sub->mem = p->sub->mem->next; + if (p->sub->mem) { t = p->sub->mem->type; - offset += p->sub->mem->offset; + offset = p->sub->mem->offset; goto done; } break; @@ -196,10 +209,7 @@ advance(struct initparser *p) error(&tok.loc, "too many initializers for type"); } done: - ++p->sub; - p->sub->type = typeunqual(t, NULL); - p->sub->offset = offset; - p->sub->iscur = false; + subobj(p, typeunqual(t, NULL), offset); } /* 6.7.9 Initialization */ diff --git a/qbe.c b/qbe.c @@ -928,7 +928,7 @@ aggr(struct type *t) } break; case TYPESTRUCT: - arrayforeach (&t->structunion.members, m) { + for (m = t->structunion.members; m; m = m->next) { if (typeprop(m->type) & PROPAGGR) aggr(m->type); else diff --git a/type.c b/type.c @@ -271,15 +271,25 @@ typecommonreal(struct type *t1, struct type *t2) fatal("internal error; could not find common real type"); } -struct member * -typemember(struct type *t, const char *name) +struct type * +typemember(struct type *t, const char *name, uint64_t *offset) { struct member *m; assert(t->kind == TYPESTRUCT || t->kind == TYPEUNION); - arrayforeach (&t->structunion.members, m) { - if (strcmp(m->name, name) == 0) - return m; + for (m = t->structunion.members; m; m = m->next) { + if (m->name) { + if (strcmp(m->name, name) == 0) { + *offset += m->offset; + return m->type; + } + } else { + t = typemember(m->type, name, offset); + if (t) { + *offset += m->offset; + return t; + } + } } return NULL; } diff --git a/type.h b/type.h @@ -45,6 +45,7 @@ struct member { char *name; struct type *type; uint64_t offset; + struct member *next; }; struct type { @@ -84,7 +85,7 @@ struct type { } func; struct { char *tag; - struct array members; + struct member *members; } structunion; }; }; @@ -102,7 +103,7 @@ struct type *typecommonreal(struct type *, struct type *); struct type *typeargpromote(struct type *); struct type *typeintpromote(struct type *); enum typeproperty typeprop(struct type *); -struct member *typemember(struct type *, const char *name); +struct type *typemember(struct type *, const char *, uint64_t *); struct parameter *mkparam(char *, struct type *);