diff options
author | Michael Forney <mforney@mforney.org> | 2019-04-17 19:13:08 -0700 |
---|---|---|
committer | Michael Forney <mforney@mforney.org> | 2019-04-17 20:11:06 -0700 |
commit | 7569343621ce0257a239e24290557e11e31dc119 (patch) | |
tree | cef551648642c3ee7888d18440c77a752118de66 | |
parent | 2833c0041d669bc1ba7a6d13e7f92c23b84e04ae (diff) |
Fix bit-field offsets in unions
-rw-r--r-- | decl.c | 38 | ||||
-rw-r--r-- | test/bitfield-union.c | 4 | ||||
-rw-r--r-- | test/bitfield-union.qbe | 1 |
3 files changed, 29 insertions, 14 deletions
@@ -684,21 +684,31 @@ addmember(struct structbuilder *b, struct qualtype mt, char *name, int align, ui error(&tok.loc, "bit-field with zero width must not have declarator"); if (width > mt.type->size * 8) error(&tok.loc, "bit-field exceeds width of underlying type"); - /* calculate end of the storage-unit for this bit-field */ - end = ALIGNUP(t->size, mt.type->size); - if (!width || width > (end - t->size) * 8 + b->bits) { - /* no room, allocate a new storage-unit */ - t->size = end; - b->bits = 0; - } - if (m) { - m->offset = ALIGNDOWN(t->size - !!b->bits, mt.type->size); - m->bits.before = (t->size - m->offset) * 8 - b->bits; - m->bits.after = mt.type->size * 8 - width - m->bits.before; - } - t->size += (width - b->bits + 7) / 8; - b->bits = (b->bits - width) % 8; align = mt.type->align; + if (t->kind == TYPESTRUCT) { + /* calculate end of the storage-unit for this bit-field */ + end = ALIGNUP(t->size, mt.type->size); + if (!width || width > (end - t->size) * 8 + b->bits) { + /* no room, allocate a new storage-unit */ + t->size = end; + b->bits = 0; + } + if (m) { + m->offset = ALIGNDOWN(t->size - !!b->bits, mt.type->size); + m->bits.before = (t->size - m->offset) * 8 - b->bits; + m->bits.after = mt.type->size * 8 - width - m->bits.before; + } + t->size += (width - b->bits + 7) / 8; + b->bits = (b->bits - width) % 8; + } else { + if (m) { + m->offset = 0; + m->bits.before = 0; + m->bits.after = mt.type->size * 8 - width; + } + if (t->size < mt.type->size) + t->size = mt.type->size; + } } if (t->align < align) t->align = align; diff --git a/test/bitfield-union.c b/test/bitfield-union.c new file mode 100644 index 0000000..f366ec8 --- /dev/null +++ b/test/bitfield-union.c @@ -0,0 +1,4 @@ +union { + int x : 5; + int y : 10; +} u = {.y = 123}; diff --git a/test/bitfield-union.qbe b/test/bitfield-union.qbe new file mode 100644 index 0000000..95d3861 --- /dev/null +++ b/test/bitfield-union.qbe @@ -0,0 +1 @@ +export data $u = align 4 { b 123, z 3 } |