aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Forney <mforney@mforney.org>2019-02-12 13:56:50 -0800
committerMichael Forney <mforney@mforney.org>2019-02-12 13:56:50 -0800
commit090ae821ce8a075e13ebf47c04e4e2781c295283 (patch)
tree2e3fdd4d6a6bc83bb354fd01c8f9831052ffb64d
parent07e3ee1cf0851129eeb51e671819f7f550ec1e4c (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.c65
-rw-r--r--tests/nested-array.c1
-rw-r--r--tests/nested-array.qbe1
-rw-r--r--type.c8
-rw-r--r--type.h5
-rw-r--r--util.c11
-rw-r--r--util.h1
7 files changed, 56 insertions, 36 deletions
diff --git a/decl.c b/decl.c
index bd9090b..31eb0b9 100644
--- a/decl.c
+++ b/decl.c
@@ -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 }
diff --git a/type.c b/type.c
index db65088..89f4d0d 100644
--- a/type.c
+++ b/type.c
@@ -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;
diff --git a/type.h b/type.h
index 662aa44..2406974 100644
--- a/type.h
+++ b/type.h
@@ -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 {
diff --git a/util.c b/util.c
index 1e44194..22300ba 100644
--- a/util.c
+++ b/util.c
@@ -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;
diff --git a/util.h b/util.h
index 50b8f49..ae70938 100644
--- a/util.h
+++ b/util.h
@@ -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))