diff options
author | Michael Forney <mforney@mforney.org> | 2019-02-12 13:56:50 -0800 |
---|---|---|
committer | Michael Forney <mforney@mforney.org> | 2019-02-12 13:56:50 -0800 |
commit | 090ae821ce8a075e13ebf47c04e4e2781c295283 (patch) | |
tree | 2e3fdd4d6a6bc83bb354fd01c8f9831052ffb64d | |
parent | 07e3ee1cf0851129eeb51e671819f7f550ec1e4c (diff) |
Fix nested arrays
We need to traverse the type hierarchy from inside to out to calculate
size/alignment of arrays.
-rw-r--r-- | decl.c | 65 | ||||
-rw-r--r-- | tests/nested-array.c | 1 | ||||
-rw-r--r-- | tests/nested-array.qbe | 1 | ||||
-rw-r--r-- | type.c | 8 | ||||
-rw-r--r-- | type.h | 5 | ||||
-rw-r--r-- | util.c | 11 | ||||
-rw-r--r-- | util.h | 1 |
7 files changed, 56 insertions, 36 deletions
@@ -413,31 +413,34 @@ istypename(struct scope *s, const char *name) } static void -declaratortypes(struct scope *s, struct partialtype *result, char **name, bool allowabstract) +declaratortypes(struct scope *s, struct list *result, char **name, bool allowabstract) { - struct partialtype prefix1 = {NULL, &prefix1.outer}, prefix2 = {NULL, &prefix2.outer}; + struct list *ptr; struct type *t; struct parameter **p; uint64_t i; enum typequalifier tq; while (consume(TMUL)) { - t = mkpointertype(result->outer); + t = mkpointertype(NULL); + listinsert(result, &t->link); tq = QUALNONE; while (typequal(&tq)) ; - if (!result->outer) - result->inner = &t->base; - result->outer = mkqualifiedtype(t, tq); + if (tq) { + t = mkqualifiedtype(NULL, tq); + listinsert(result, &t->link); + } } if (name) *name = NULL; + ptr = result->next; switch (tok.kind) { case TLPAREN: next(); if (allowabstract && tok.kind != TMUL && (tok.kind != TIDENT || istypename(s, tok.lit))) goto func; - declaratortypes(s, &prefix1, name, allowabstract); + declaratortypes(s, result, name, allowabstract); expect(TRPAREN, "after parenthesized declarator"); break; case TIDENT: @@ -497,8 +500,7 @@ declaratortypes(struct scope *s, struct partialtype *result, char **name, bool a break; } expect(TRPAREN, "to close function declarator"); - *prefix2.inner = t; - prefix2.inner = &t->base; + listinsert(ptr->prev, &t->link); break; case TLBRACK: /* array declarator */ next(); @@ -518,46 +520,45 @@ declaratortypes(struct scope *s, struct partialtype *result, char **name, bool a i = intconstexpr(s); expect(TRBRACK, "after array length"); } + if (tq) { + t = mkqualifiedtype(NULL, tq); + listinsert(ptr->prev, &t->link); + } t = mkarraytype(NULL, i); - *prefix2.inner = mkqualifiedtype(t, tq); - prefix2.inner = &t->base; + listinsert(ptr->prev, &t->link); break; default: - goto done; + return; } } -done: - if (prefix2.outer) { - if (result->inner == &result->outer) - result->inner = prefix2.inner; - *prefix2.inner = result->outer; - result->outer = prefix2.outer; - } - if (prefix1.outer) { - if (result->inner == &result->outer) - result->inner = prefix1.inner; - *prefix1.inner = result->outer; - result->outer = prefix1.outer; - } } static struct type * -declarator(struct scope *s, struct type *t, char **name, bool allowabstract) +declarator(struct scope *s, struct type *base, char **name, bool allowabstract) { - struct partialtype result = {NULL, &result.outer}; + struct type *t; + struct list result = {&result, &result}, *l, *prev; declaratortypes(s, &result, name, allowabstract); - *result.inner = t; - for (t = result.outer; t; t = t->base) { + for (l = result.prev; l != &result; l = prev) { + prev = l->prev; + t = listelement(l, struct type, link); + t->base = base; switch (t->kind) { case TYPEARRAY: - t->align = t->base->align; - t->size = t->base->size * t->array.length; // XXX: overflow? + t->align = base->align; + t->size = base->size * t->array.length; // XXX: overflow? + break; + case TYPEQUALIFIED: + t->align = base->align; + t->size = base->size; + t->repr = base->repr; break; } + base = t; } - return result.outer; + return base; } static struct type * diff --git a/tests/nested-array.c b/tests/nested-array.c new file mode 100644 index 0000000..3c62258 --- /dev/null +++ b/tests/nested-array.c @@ -0,0 +1 @@ +int x[2][3];
\ No newline at end of file diff --git a/tests/nested-array.qbe b/tests/nested-array.qbe new file mode 100644 index 0000000..cfc6bed --- /dev/null +++ b/tests/nested-array.qbe @@ -0,0 +1 @@ +export data $x = align 4 { z 24 } @@ -53,9 +53,11 @@ mkqualifiedtype(struct type *t, enum typequalifier tq) if (tq) { t = mktype(TYPEQUALIFIED, t); t->qualified.kind = tq; - t->size = t->base->size; - t->align = t->base->align; - t->repr = t->base->repr; + if (t->base) { + t->size = t->base->size; + t->align = t->base->align; + t->repr = t->base->repr; + } // XXX: incomplete? } return t; @@ -52,7 +52,10 @@ struct type { int align; uint64_t size; struct representation *repr; - struct type *base; + union { + struct type *base; + struct list link; /* used only during construction of type */ + }; _Bool incomplete; union { struct { @@ -126,6 +126,17 @@ listinsert(struct list *list, struct list *new) } void +listinsertlist(struct list *list, struct list *new) +{ + if (new->next == new) + return; + new->next->prev = list; + new->prev->next = list; + list->next->prev = new->prev; + list->next = new->next; +} + +void listremove(struct list *list) { list->next->prev = list->prev; @@ -22,6 +22,7 @@ void *xmalloc(size_t); char *progname(char *, char *); void listinsert(struct list *, struct list *); +void listinsertlist(struct list *, struct list *); void listremove(struct list *); #define listelement(list, type, member) (type *)((char *)list - offsetof(type, member)) |