aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2025-11-26 10:40:29 +0100
committerlemon <lsof@mailbox.org>2025-11-26 10:40:29 +0100
commit31c91845d07f47d71950dbc35e8d2620268bcbd3 (patch)
tree76de689201bbd51c8a694ea3f6e84d599444edbc
parentb190f33220890babd0b753ae6a9fcfcf1cf026a9 (diff)
c: fix elided-braces initializers for nested unions
For example in ```c struct {int a; union { int b,c; }; int d; } X = {1,2,3}; ``` Fields `a`,`b`,`d` must get initialized to 1,2,3. Not `c`
-rw-r--r--c/c.c21
1 files changed, 16 insertions, 5 deletions
diff --git a/c/c.c b/c/c.c
index 6d0ee0e..fc5ad6f 100644
--- a/c/c.c
+++ b/c/c.c
@@ -1124,11 +1124,11 @@ commaexpr(struct comp *cm)
static uint
nmemb(union type ty)
{
- if (ty.t == TYARRAY)
- return typearrlen(ty) ? typearrlen(ty) : -1u;
- if (isagg(ty))
- return typedata[ty.dat].nmemb;
- return 1;
+ switch (ty.t) {
+ case TYARRAY: return typearrlen(ty) ? typearrlen(ty) : -1u;
+ case TYUNION: case TYSTRUCT: return typedata[ty.dat].nmemb;
+ default: return 1;
+ }
}
static bool
@@ -1389,6 +1389,10 @@ iniadvance(struct initparser *ip, struct initcur *c, const struct span *span)
static void
inifocus(struct initparser *ip, struct comp *cm, const struct span *span, uint idx)
{
+ while (idx >= nmemb(ip->sub->ty) && ip->sub != ip->cur) {
+ --ip->sub;
+ idx = ip->sub->idx;
+ }
uint off, bitsiz, bitoff;
union type targ = membertype(&off, &bitsiz, &bitoff, ip->sub->ty, idx);
struct initcur *next = iniadvance(ip, ip->cur, span);
@@ -1678,6 +1682,13 @@ initializer(struct comp *cm, union type *ty, enum evalmode ev, bool globl,
ininext(ip, cm);
}
match(cm, NULL, ',');
+ if (peek(cm, &tk) != '}' && ip->sub->ty.t == TYUNION) {
+ if (ip->sub == ip->cur) {
+ warn(&tk.span, "excess elements in union initializer");
+ } else while (ip->sub != ip->cur && ip->sub->ty.t == TYUNION) {
+ --ip->sub;
+ }
+ }
}
if (ip->dyn) {
enum section sec;