aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Forney <mforney@mforney.org>2019-02-15 01:39:53 -0800
committerMichael Forney <mforney@mforney.org>2019-02-15 19:52:18 -0800
commit8ffedb1f24804c9c13121a12b3802610f2b6f9df (patch)
treeeafe054135582b264bf021e1b2d414351b023ca1
parente477588215b222bf42d72385d9808db56e0bfce0 (diff)
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.
-rw-r--r--decl.c74
-rw-r--r--expr.c16
-rw-r--r--init.c80
-rw-r--r--qbe.c2
-rw-r--r--type.c20
-rw-r--r--type.h5
6 files changed, 113 insertions, 84 deletions
diff --git a/decl.c b/decl.c
index 03dfb3d..3e574b2 100644
--- 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
index 88cf764..28dc68f 100644
--- 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
index 2335db4..2ccf058 100644
--- 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
index ad82331..670ad83 100644
--- 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
index c9a3a1e..7414f0a 100644
--- 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
index 82c3929..d02df31 100644
--- 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 *);