diff options
| author | 2026-04-13 09:45:28 +0200 | |
|---|---|---|
| committer | 2026-04-13 09:45:28 +0200 | |
| commit | b9de0c34a285aa0e3a7cfffb542732819adafd61 (patch) | |
| tree | 55d54912f64f521da36240167934287ec26a4ee4 /src | |
| parent | db576fab9f4eed8591c332d8353eed26c517ff36 (diff) | |
frontend: accept zero size arrays and empty aggregates
GNU extension. Previously was overloading arraylength==0 to mean unsized
array, now they are distinct with the type flag TFUNKNOWN marking
unsized arrays & aggregates.
Diffstat (limited to 'src')
| -rw-r--r-- | src/c.c | 42 | ||||
| -rw-r--r-- | src/c_type.c | 20 | ||||
| -rw-r--r-- | src/c_type.h | 8 |
3 files changed, 39 insertions, 31 deletions
@@ -345,7 +345,6 @@ finddecl(CComp *cm, internstr name) static Type gettagged(CComp *cm, Span *span, enum typetag tt, internstr name, bool dodef) { - TypeData td = {0}; assert(name); for (Env *e = cm->env; e; e = e->up) { for (Tagged *l = NULL; envitertagged(&l, e);) { @@ -361,14 +360,12 @@ gettagged(CComp *cm, Span *span, enum typetag tt, internstr name, bool dodef) warn(span, "forward-declared enum is an extension"); } Break2: - td.t = tt; - return envaddtagged(cm->env, mktagtype(name, &td), span)->ty; + return envaddtagged(cm->env, mktagtype(name, &(TypeData){tt, TFUNKNOWN}), span)->ty; } static Type deftagged(CComp *cm, Span *span, enum typetag tt, internstr name, Type ty) { - TypeData td = {0}; assert(name); for (Tagged *l = NULL; envitertagged(&l, cm->env);) { if (name == tagtypetags[typedata[l->ty.dat].id]) { @@ -376,8 +373,7 @@ deftagged(CComp *cm, Span *span, enum typetag tt, internstr name, Type ty) return l->ty; } } - td.t = tt; - return envaddtagged(cm->env, ty.t ? ty : mktagtype(name, &td), span)->ty; + return envaddtagged(cm->env, ty.t ? ty : mktagtype(name, &(TypeData){tt, TFUNKNOWN}), span)->ty; } /*********************/ @@ -398,8 +394,7 @@ argpromote(Type t) { if (isint(t)) t.t = intpromote(t.t); else if (t.t == TYFLOAT) t.t = TYDOUBLE; - else if (t.t == TYARRAY) return mkptrtype(typechild(t), t.flag & TFCHLDQUAL); - else if (t.t == TYFUNC) return mkptrtype(t, 0); + else if (t.t == TYARRAY || t.t == TYFUNC) t = typedecay(t); return t; } @@ -1319,7 +1314,7 @@ static uint nmemb(Type ty) { switch (ty.t) { - case TYARRAY: return typearrlen(ty) ? typearrlen(ty) : -1u; + case TYARRAY: return isincomplete(ty) ? -1u : typearrlen(ty); case TYUNION: case TYSTRUCT: return typedata[ty.dat].nmemb; default: return 1; } @@ -1613,7 +1608,7 @@ ininext(InitParser *ip, CComp *cm) Retry: targ = membertype(&off, &bitsiz, &bitoff, ip->sub->ty, ip->sub->idx); - if (isagg(ip->sub->ty) && targ.t == TYARRAY && !typearrlen(targ)) { + if (isagg(ip->sub->ty) && targ.t == TYARRAY && isincomplete(targ)) { error(&ex.span, "cannot initialize flexible array member"); ++ip->sub->idx; return; @@ -1876,8 +1871,8 @@ initializer(CComp *cm, Type *ty, enum evalmode ev, bool globl, if (isincomplete(*ty)) { uint len = ip->arrlen > ip->cur->idx ? ip->arrlen : ip->cur->idx; - if (len == 0) - error(&span, "array cannot have zero length"); + if (len == 0 && ccopt.pedant) + warn(&span, "zero size array is an extension"); *ty = mkarrtype(typechild(*ty), ty->flag & TFCHLDQUAL, len); } Dynfix: @@ -1906,8 +1901,8 @@ initializer(CComp *cm, Type *ty, enum evalmode ev, bool globl, uint siz; if (isincomplete(*ty)) { uint len = ip->arrlen > ip->cur->idx ? ip->arrlen : ip->cur->idx; - if (!len) - error(&span, "initializer creates a zero-sized array"); + if (!len && ccopt.pedant) + warn(&span, "initializer creates a zero size array"); *ty = mkarrtype(typechild(*ty), ty->flag & TFCHLDQUAL, len); } @@ -2011,7 +2006,7 @@ buildagg(CComp *cm, enum typetag tt, internstr name, int id) td.flexi = 0; error(&flexspan, "flexible array member is not at end of struct"); } - if (!isunion && decl.ty.t == TYARRAY && !typearrlen(decl.ty)) { + if (!isunion && decl.ty.t == TYARRAY && typearrlen(decl.ty) == 0) { td.flexi = 1; flexspan = decl.span; } else if (isincomplete(decl.ty)) { @@ -2098,14 +2093,16 @@ buildagg(CComp *cm, enum typetag tt, internstr name, int id) } while (st.more); } if (td.flexi && fld.n == 1) - error(&flexspan, "flexible array member in otherwise empty aggregate"); + warn(&flexspan, "flexible array member in otherwise empty aggregate"); if (td.flexi && ccopt.cstd < STDC99 && ccopt.pedant) warn(&flexspan, "flexible array member in %M is an extension"); if (fld.n == 0) { NamedField dummy = { intern(""), { mktype(TYCHAR), 0 }}; - error(&tk.span, "%s cannot have zero members", tag); + if (ccopt.pedant) + warn(&tk.span, "%s with zero members is an extension", tag); vpush(&fld, dummy); - td.siz = td.align = 1; + td.siz = 0; + td.align = 1; } td.siz = alignup(td.siz, td.align); td.fld = fld.p; @@ -2768,7 +2765,7 @@ declarator(DeclState *st, CComp *cm, Span span0) { else if (decl.ty.t == TYFUNC) error(&l->span, "array has element has function type '%ty'", decl.ty); if (l->count.t == EARRAYUNSIZED) /* unsized '[]' */ - decl.ty = mkarrtype(decl.ty, decl.qual, 0); + decl.ty = mkunszarrtype(decl.ty, decl.qual); else { uint n = 0; Expr *ex = &l->count; @@ -2781,10 +2778,8 @@ declarator(DeclState *st, CComp *cm, Span span0) { } else if (ex->u > (1ull << (8*sizeof n)) - 1) { error(&ex->span, "array too long (%ul)", ex->u); } else if (ex->u == 0) { - /* when struct field, silently accept zero-length as synonym of '[]' for flexible array member */ - if (l->prev != &list || st->kind != DFIELD) { - warn(&ex->span, "array cannot have zero length"); - } + if (ccopt.pedant) + warn(&ex->span, "zero size array is an extension"); } else { n = ex->u; } @@ -4735,6 +4730,7 @@ docomp(CComp *cm) cm->env = &toplevel; } if (!cvalistty.t) { + /* XXX hardcoded va_list impl */ TypeData td = { .t = TYSTRUCT, .siz = targ_valistsize, .align = targ_primalign[TYPTR], .nmemb = 1, .fld = &(NamedField){intern("-"), {mkarrtype(mktype(TYPTR), 0, 3)}} diff --git a/src/c_type.c b/src/c_type.c index 5853eb8..ef4770d 100644 --- a/src/c_type.c +++ b/src/c_type.c @@ -105,11 +105,13 @@ interntd(const TypeData *td) *slot = *td; switch (slot->t) { case TYENUM: + assert(!(td->flag & TFUNKNOWN) || (!td->var && !td->siz)); if (slot->var) slot->var = alloccopy(&datarena, td->var, nmemb * sizeof *slot->var, 0); break; case TYSTRUCT: case TYUNION: + assert(!(td->flag & TFUNKNOWN) || (td->nmemb == 0 && !td->siz)); if (slot->fld) slot->fld = alloccopy(&datarena, td->fld, nmemb * sizeof *slot->fld, 0); break; @@ -132,12 +134,11 @@ isincomplete(Type t) { switch (t.t) { case TYVOID: return 1; - case TYARRAY: return !typearrlen(t); + case TYARRAY: return t.flag & TFUNKNOWN; + case TYENUM: case TYSTRUCT: case TYUNION: - return typedata[t.dat].nmemb == 0; - case TYENUM: - return !typedata[t.dat].backing; + return typedata[t.dat].flag & TFUNKNOWN; } return 0; } @@ -197,6 +198,15 @@ mkarrtype(Type t, int qual, uint n) } Type +mkunszarrtype(Type t, int qual) +{ + if (isprim(t)) + return mktype(TYARRAY, .flag = TFCHLDPRIM | (qual & TFCHLDQUAL) | TFUNKNOWN, .child = t.t); + return mktype(TYARRAY, .flag = TFUNKNOWN | (qual & TFCHLDQUAL), + .dat = interntd(&(TypeData) { TYARRAY, TFUNKNOWN, .child = t })); +} + +Type mkfntype(Type ret, uint n, const Type *par, bool kandr, bool variadic) { TypeData td = { TYFUNC, .ret = ret, .nmemb = n, .param = par }; @@ -214,7 +224,7 @@ completetype(internstr name, int id, TypeData *td) assert(tagtypetags[id] == name && "bad redefn"); else tagtypetags[id] = name; - return mktype(td->t, .dat = interntd(td)); + return mktype(td->t, .flag = td->flag, .dat = interntd(td)); } Type diff --git a/src/c_type.h b/src/c_type.h index 6f9a265..6ef1bc3 100644 --- a/src/c_type.h +++ b/src/c_type.h @@ -25,12 +25,12 @@ enum typeflagmask { TFCHLDQUAL = 3, TFCHLDPRIM = 1<<2, TFCHLDISDAT = 1<<3, + TFUNKNOWN = 1<<4, /* array of unknown size, tagged type of unknown content */ }; - typedef union Type { struct { uchar t; /* type tag */ - uchar flag; + uchar flag; /* enum typeflagmask */ union { struct { uchar child; /* prim type tag */ @@ -85,6 +85,7 @@ typedef struct { typedef struct TypeData { uchar t; + uchar flag; ushort id; union { Type child; @@ -127,6 +128,7 @@ uint typesize(Type); uint typealign(Type); Type mkptrtype(Type, int qual); Type mkarrtype(Type t, int qual, uint n); +Type mkunszarrtype(Type t, int qual); Type mkfntype(Type ret, uint n, const Type *, bool kandr, bool variadic); Type mktagtype(internstr name, TypeData *td); bool getfield(FieldData *res, Type, internstr); @@ -141,7 +143,7 @@ typechild(Type t) if (t.t == TYENUM) return mktype(typedata[t.dat].backing); if (t.flag & TFCHLDPRIM) return mktype(t.child); if (t.flag & TFCHLDISDAT) { - Type chld = mktype(typedata[t.dat].t, .dat = t.dat); + Type chld = mktype(typedata[t.dat].t, .flag = typedata[t.dat].flag, .dat = t.dat); return chld; } return typedata[t.dat].child; |