diff options
| -rw-r--r-- | c/c.c | 69 | ||||
| -rw-r--r-- | io.c | 2 | ||||
| -rw-r--r-- | test/13-c11.c | 5 | ||||
| -rw-r--r-- | type.c | 12 | ||||
| -rw-r--r-- | type.h | 29 |
5 files changed, 56 insertions, 61 deletions
@@ -115,6 +115,7 @@ struct declstate { empty; /* nothing decl (';') */ const char **pnames; /* param names for function definition */ struct span *pspans; /* param spans ditto */ + uchar *pqual; /* param quals ditto */ }; static struct decl pdecl(struct declstate *st, struct comp *cm); @@ -701,7 +702,7 @@ callexpr(struct comp *cm, const struct span *span_, const struct expr *callee) if (callee->t == ESYM && ty.t == IMPLICITFUNCTY) { /* implicit function decl.. */ const char *name = (void *)callee->sym; struct decl decl = { - (ty = mkfntype(mktype(TYINT), 0, NULL, NULL, /* kandr */ 1, 0)), + (ty = mkfntype(mktype(TYINT), 0, NULL, /* kandr */ 1, 0)), .scls = SCEXTERN, .span = span, .name = name, .sym = name }; warn(&span, "call to undeclared function '%s'", name); @@ -898,8 +899,9 @@ static struct expr initializer(struct comp *cm, union type *ty, enum evalmode ev /* parse an expression with the given operator precedence */ /* param ident is a kludge to support block labels without backtracking or extra lookahead * see stmt() */ +enum exprctx { EFROMSTMT = 1, EARRAYCOUNT }; static struct expr -exprparse(struct comp *cm, int prec, const struct token *ident, bool fromstmt) +exprparse(struct comp *cm, int prec, const struct token *ident, enum exprctx ctx) { struct token tk; struct span span; @@ -930,8 +932,14 @@ exprparse(struct comp *cm, int prec, const struct token *ident, bool fromstmt) Unary: switch (lex(cm, &tk)) { /* unary operators (gather) */ + case '*': + if (ctx == EARRAYCOUNT && peek(cm, NULL) == ']') { + /* kludge for C99 `int x[*]` (unk VLA size) */ + return (struct expr) { 0, .span = tk.span }; + } + /* fallthru */ case '+': case '-': case '~': case '!': - case '*': case '&': case TKINC: case TKDEC: + case '&': case TKINC: case TKDEC: Unops: unops[nunop].span = tk.span; unops[nunop].t0 = 0; @@ -1031,7 +1039,7 @@ Unary: ex = vaargexpr(cm, &span); break; default: - fatal(&tk.span, "expected %s (near %'tk)", fromstmt ? "statement" : "expression", &tk); + fatal(&tk.span, "expected %s (near %'tk)", ctx == EFROMSTMT ? "statement" : "expression", &tk); } ppostfixopers(cm, &ex); @@ -1153,6 +1161,12 @@ expr(struct comp *cm) } static struct expr +arraycountexpr(struct comp *cm) +{ + return exprparse(cm, bintab['='].prec, NULL, EARRAYCOUNT); /* non-comma expr, or lone '*' */ +} + +static struct expr constantexpr(struct comp *cm) { return exprparse(cm, bintab['?'].prec, NULL, 0); /* conditional-expr */ @@ -2310,7 +2324,7 @@ static bool usingdeclparamtmp; static union type declparamtmp[16]; static const char *declpnamestmp[16]; static struct span declpspanstmp[16]; -static uchar declpqualtmp[tdqualsiz(16)]; +static uchar declpqualtmp[16]; static void declinsert(struct decllist *list, const struct decllist *node) @@ -2391,9 +2405,20 @@ decltypes(struct comp *cm, struct decllist *list, const char **name, struct span if (match(cm, &tk, '[')) { node.span = tk.span; uint n = 0; + int q = 0; + bool statik = 0; + if (in_range(peek(cm, &tk), TKWBEGIN_, TKWEND_)) { + q = cvqual(cm); + statik = match(cm, NULL, TKWstatic); + q |= cvqual(cm); + } + (void)q, (void)statik; /* stub */ + if (!match(cm, &tk, ']')) { - struct expr ex = expr(cm); - if (!eval(&ex, EVINTCONST)) { + struct expr ex = arraycountexpr(cm); + if (!ex.t) { /* treat ['*'] as [0] */ + n = 0; + } else if (!eval(&ex, EVINTCONST)) { error(&ex.span, "array length is not an integer constant"); } else if (typesize(ex.ty) < 8 && ex.i < 0) { error(&ex.span, "array length is negative"); @@ -2417,7 +2442,6 @@ decltypes(struct comp *cm, struct decllist *list, const char **name, struct span vec_of(uchar) qual = {0}; vec_of(const char *) names = {0}; vec_of(struct span) spans = {0}; - bool anyqual = 0; if (!usingdeclparamtmp) { usingdeclparamtmp = 1; @@ -2456,17 +2480,13 @@ decltypes(struct comp *cm, struct decllist *list, const char **name, struct span vpush(¶ms, decl.ty); vpush(&names, decl.name); vpush(&spans, decl.span); - if (decl.qual) { - anyqual = 1; - while (qual.n < tdqualsiz(params.n)) vpush(&qual, 0); - tdsetqual(qual.p, params.n-1, decl.qual); - } + vpush(&qual, decl.qual); if (isincomplete(decl.ty)) { if (params.n > 1 || decl.ty.t != TYVOID || decl.qual || decl.name || peek(cm, &tk) != ')') { error(&decl.span, "function parameter #%d has incomplete type (%tq)", - params.n, decl.ty, tdgetqual(qual.p, params.n-1)); + params.n, decl.ty, qual.p[params.n-1]); } } } @@ -2481,15 +2501,15 @@ decltypes(struct comp *cm, struct decllist *list, const char **name, struct span } if (node.kandr && ccopt.cstd != STDC89 && params.n > 0) { warn(&node.span, "K&R function prototype is deprecated"); - } else if (params.n == 1 && params.p[0].t == TYVOID && !qual.n && !names.p[0]) { /* (void) */ + } else if (params.n == 1 && params.p[0].t == TYVOID && !qual.p[0] && !names.p[0]) { /* (void) */ vfree(¶ms); vfree(&names); vfree(&spans); + vfree(&qual); } - if (anyqual) while (qual.n < tdqualsiz(params.n)) vpush(&qual, 0); node.t = TYFUNC; node.param = params.n ? params.p : NULL; - node.pqual = anyqual ? qual.p : NULL; + node.pqual = qual.n ? qual.p : NULL; node.pnames = params.n ? names.p : NULL; node.pspans = params.n ? spans.p : NULL; node.npar = params.n; @@ -2538,15 +2558,16 @@ declarator(struct declstate *st, struct comp *cm, struct span span0) { error(&decl.span, "function cannot return array type '%ty'", decl.ty); if (l->kandr && ccopt.cstd > STDC89 && (ccopt.cstd >= STDC23 || ccopt.pedant)) warn(&l->span, "function declaration without a prototype is deprecated"); - decl.ty = mkfntype(decl.ty, l->npar, l->param, l->pqual, l->kandr, l->variadic); + decl.ty = mkfntype(decl.ty, l->npar, l->param, l->kandr, l->variadic); if (l->param != declparamtmp) free(l->param); - if (l->pqual != declpqualtmp) free(l->pqual); if (l->prev == &list && l->npar) { /* last */ st->pnames = alloccopy(&cm->fnarena, l->pnames, l->npar * sizeof(char *), 0); st->pspans = alloccopy(&cm->fnarena, l->pspans, l->npar * sizeof(struct span), 0); + st->pqual = l->pqual ? alloccopy(&cm->fnarena, l->pqual, l->npar, 1) : NULL; decl.inlin = st->fninline; decl.noret = st->fnnoreturn; } + if (l->pqual != declpqualtmp) free(l->pqual); if (l->pnames != declpnamestmp) free(l->pnames); if (l->pspans != declpspanstmp) free(l->pspans); if (l->param == declparamtmp) usingdeclparamtmp = 0; @@ -3776,7 +3797,7 @@ stmt(struct comp *cm, struct function *fn) } else { assert(tk.t == TKIDENT); /* kludge for no backtracking and no lookahead */ - ex = exprparse(cm, 1, &tk, 1); + ex = exprparse(cm, 1, &tk, EFROMSTMT); stmtterm(cm); EMITS expreffects(fn, &ex); return fn->curblk == NULL; @@ -4055,7 +4076,7 @@ stmt(struct comp *cm, struct function *fn) stmtterm(cm); break; default: - ex = exprparse(cm, 1, NULL, 1); + ex = exprparse(cm, 1, NULL, EFROMSTMT); stmtterm(cm); EMITS expreffects(fn, &ex); break; @@ -4200,7 +4221,7 @@ block(struct comp *cm, struct function *fn) } static void -function(struct comp *cm, struct function *fn, const char **pnames, const struct span *pspans) +function(struct comp *cm, struct function *fn, const char **pnames, const struct span *pspans, uchar *pquals) { const struct typedata *td = &typedata[fn->fnty.dat]; const bool doemit = fn->curblk; @@ -4220,7 +4241,7 @@ function(struct comp *cm, struct function *fn, const char **pnames, const struct /* add parameters to symbol table and create prologue (arguments) block */ for (int i = 0; i < td->nmemb; ++i) { if (pnames[i]) { - struct decl arg = { .ty = td->param[i], .qual = tdgetqual(td->quals, i), + struct decl arg = { .ty = td->param[i], .qual = pquals ? pquals[i] : 0, .name = pnames[i], .scls = SCAUTO, .span = pspans[i] }; EMITS { if (isscalar(arg.ty)) { @@ -4334,7 +4355,7 @@ docomp(struct comp *cm) decl.isdef = 1; putdecl(cm, &decl); irinit(&fn); - function(cm, &fn, st.pnames, st.pspans); + function(cm, &fn, st.pnames, st.pspans, st.pqual); if (!nerror && ccopt.dbg.p) irdump(&fn); irfini(&fn); @@ -261,7 +261,7 @@ pritypeafter(struct wbuf *buf, union type ty, int qual) td = &typedata[ty.dat]; n += bputc(buf, '('); for (int i = 0; i < td->nmemb; ++i) { - n += bfmt(buf, "%tq", td->param[i], tdgetqual(td->quals, i)); + n += bfmt(buf, "%ty", td->param[i]); if (i < td->nmemb - 1 || td->variadic) n += bwriteS(buf, ", "); } diff --git a/test/13-c11.c b/test/13-c11.c index 479c2d7..e0302e4 100644 --- a/test/13-c11.c +++ b/test/13-c11.c @@ -15,6 +15,11 @@ int foo(int x) { else return x; } +int s(int n, int x[]); +int s(int n, int *x); +int s(int n, int (*const x)); +int s(int n, int x[*]); + struct x{int h:2;} X; int main(int argc, char **argv) { return foo(0); @@ -26,9 +26,7 @@ hashtd(const struct typedata *td) h = hashb(h, (t = td->kandr, &t), sizeof t); h = hashb(h, (t = td->variadic, &t), sizeof t); for (int i = 0; i < td->nmemb; ++i) { - uchar q = tdgetqual(td->quals, i); h = hashb(h, &td->param[i], sizeof *td->param); - h = hashb(h, &q, sizeof q); } break; default: @@ -56,9 +54,7 @@ tdequ(const struct typedata *a, const struct typedata *b) if (a->variadic != b->variadic) return 0; if (a->kandr != b->kandr) return 0; for (int i = 0; i < a->nmemb; ++i) { - if (!a->quals != !b->quals || a->param[i].bits != b->param[i].bits) - return 0; - if (a->quals && tdgetqual(a->quals, i) != tdgetqual(b->quals, i)) + if (a->param[i].bits != b->param[i].bits) return 0; } return 1; @@ -98,8 +94,6 @@ interntd(const struct typedata *td) case TYFUNC: if (slot->param) slot->param = alloccopy(&datarena, td->param, nmemb * sizeof *slot->param, 0); - if (slot->quals) - slot->quals = alloccopy(&datarena, td->quals, tdqualsiz(nmemb), 1); } return i; } else if (tdequ(slot, td)) { @@ -179,9 +173,9 @@ mkarrtype(union type t, int qual, uint n) } union type -mkfntype(union type ret, uint n, const union type *par, const uchar *qual, bool kandr, bool variadic) +mkfntype(union type ret, uint n, const union type *par, bool kandr, bool variadic) { - struct typedata td = { TYFUNC, .ret = ret, .nmemb = n, .param = par, .quals = qual }; + struct typedata td = { TYFUNC, .ret = ret, .nmemb = n, .param = par }; td.kandr = kandr, td.variadic = variadic; return mktype(TYFUNC, .dat = interntd(&td)); } @@ -87,19 +87,8 @@ struct typedata { ushort id; union { union type child; - struct { /* functions */ - const uchar *quals; /* packed N x 2bit array (NULL if no param has quals) */ - const union type *param; - }; + const union type *param; /* functions */ struct { /* aggregates */ - /* struct fieldmap { - union { - struct field *fs; - int *is; - }; - const char **k; - uint ; - } *fmap; */ struct namedfield *fld; }; struct { /* enum */ @@ -131,26 +120,12 @@ struct typedata { extern struct typedata typedata[]; extern const char *ttypenames[/*id*/]; -#define tdqualsiz(nmemb) ((nmemb)/4 + ((nmemb)%4 != 0)) -static inline int -tdgetqual(const uchar *pqual, uint idx) -{ - return pqual ? pqual[idx/4] >> 2*(idx%4) & 3 : 0; -} -static inline void -tdsetqual(uchar *pqual, uint idx, int qual) -{ - assert(pqual); - pqual[idx/4] &= ~(3 << (2*(idx%4))); - pqual[idx/4] |= (qual&3) << (2*(idx%4)); -} - bool isincomplete(union type); uint typesize(union type); uint typealign(union type); union type mkptrtype(union type, int qual); union type mkarrtype(union type t, int qual, uint n); -union type mkfntype(union type ret, uint n, const union type *, const uchar *qual, bool kandr, bool variadic); +union type mkfntype(union type ret, uint n, const union type *, bool kandr, bool variadic); union type mktagtype(const char *name, struct typedata *td); bool getfield(struct fielddata *res, union type, const char *); union type completetype(const char *name, int id, struct typedata *td); |