harec

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

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:
Msrc/emit.c | 22++++++++++++++++++++--
Msrc/qtype.c | 9++++++++-
Msrc/types.c | 1+
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; }