commit b2f81197761d64a5f53d95fe4b38bfffd67b7591
parent b201f877a1bb6fad5beae7a7d4ebce450ddbfff8
Author: Drew DeVault <sir@cmpwn.com>
Date: Sun, 14 Feb 2021 10:54:11 -0500
qtype: fix tagged unions with middle zero types
If we have a type which, after sorting, looks like this:
(nonzero | void | nonzero)
qtype would have bunged up the last type.
Diffstat:
3 files changed, 29 insertions(+), 3 deletions(-)
diff --git a/src/emit.c b/src/emit.c
@@ -1,8 +1,10 @@
#include <assert.h>
#include <ctype.h>
+#include <stdlib.h>
#include <stdio.h>
#include "emit.h"
#include "qbe.h"
+#include "typedef.h"
static void
emit_qtype(const struct qbe_type *type, bool aggr, FILE *out)
@@ -29,10 +31,26 @@ emit_qtype(const struct qbe_type *type, bool aggr, FILE *out)
}
}
+static char *
+gen_typename(const struct type *type)
+{
+ size_t sz = 0;
+ char *ptr = NULL;
+ FILE *f = open_memstream(&ptr, &sz);
+ emit_type(type, f);
+ fclose(f);
+ return ptr;
+}
+
static void
-emit_type(const struct qbe_def *def, FILE *out)
+qemit_type(const struct qbe_def *def, FILE *out)
{
assert(def->kind == Q_TYPE);
+ if (def->type.base) {
+ char *tn = gen_typename(def->type.base);
+ fprintf(out, "# %s\n", tn);
+ free(tn);
+ }
fprintf(out, "type :%s =", def->name);
if (def->type.align != (size_t)-1) {
fprintf(out, " align %zu", def->type.align);
@@ -310,7 +328,7 @@ emit_def(struct qbe_def *def, FILE *out)
{
switch (def->kind) {
case Q_TYPE:
- emit_type(def, out);
+ qemit_type(def, out);
break;
case Q_FUNC:
emit_func(def, out);
diff --git a/src/qtype.c b/src/qtype.c
@@ -1,5 +1,6 @@
#include <assert.h>
#include <stdbool.h>
+#include <stdlib.h>
#include <stdio.h>
#include "gen.h"
#include "qbe.h"
@@ -121,15 +122,21 @@ tagged_qtype(struct gen_context *ctx, const struct type *type)
def->type.size = type->size - type->align;
struct qbe_field *field = &def->type.fields;
+ struct qbe_field **next = &field->next;
for (const struct type_tagged_union *tu = &type->tagged;
tu; tu = tu->next) {
if (tu->type->size == 0) {
+ if (!tu->next && *next) {
+ free(*next);
+ *next = NULL;
+ }
continue;
}
field->type = qtype_for_type(ctx, tu->type, true);
field->count = 1;
- if (tu->next && tu->next->type->size != 0) {
+ if (tu->next) {
field->next = xcalloc(1, sizeof(struct qbe_field));
+ next = &field->next;
field = field->next;
}
}
diff --git a/src/types.c b/src/types.c
@@ -407,6 +407,7 @@ type_hash(const struct type *type)
tuple; tuple = tuple->next) {
hash = fnv1a_u32(hash, type_hash(tuple->type));
}
+ break;
}
return hash;
}