From 6ce2ac20e1d9095281a233aeb778d0fa2c82dd74 Mon Sep 17 00:00:00 2001 From: lemon Date: Sun, 4 Jun 2023 23:26:06 +0200 Subject: better diagnostics --- common.h | 1 + io.c | 5 +++++ lex.c | 24 +++++++++++++++--------- main.c | 5 ++++- parse.c | 41 ++++++++++++++++++++++++++++++++--------- test.c | 11 ++++++++--- 6 files changed, 65 insertions(+), 22 deletions(-) diff --git a/common.h b/common.h index 6246f02..1b40000 100644 --- a/common.h +++ b/common.h @@ -93,6 +93,7 @@ enum cstd { }; struct option { enum cstd cstd; + bool pedant; bool trigraph; bool nocolor; }; diff --git a/io.c b/io.c index 48325d4..9156d27 100644 --- a/io.c +++ b/io.c @@ -550,6 +550,11 @@ vbfmt(struct wbuf *out, const char *fmt, va_list ap) } if (!ccopt.nocolor) n += bputc(buf, 'm'); break; + case 'M': /* cc mode */ + iowrite(buf, &"C89\0C99\0C11\0C23"[ccopt.cstd*4], 3); + n += 3; + n += bwriteS(buf, " mode"); + break; default: if (umod || lmod) { --fmt; diff --git a/lex.c b/lex.c index a41bd0d..f172c30 100644 --- a/lex.c +++ b/lex.c @@ -24,7 +24,7 @@ intern(const char *s) } } -static void +static bool identkeyword(struct token *tk, const char *s, int len) { static const struct { const char *s; enum toktag t; enum cstd cstd; } kwtab[] = { @@ -41,15 +41,17 @@ identkeyword(struct token *tk, const char *s, int len) cmp = strcmp(kwtab[i].s, s); if (cmp < 0) l = i + 1; else if (cmp > 0) h = i - 1; - else if (kwtab[i].cstd <= ccopt.cstd) { + else if (kwtab[i].cstd <= ccopt.cstd || kwtab[i].s[0] == '_') { + /* allow future keywords but only if they begin with _ */ tk->t = kwtab[i].t; tk->s = kwtab[i].s; - return; + return kwtab[i].cstd <= ccopt.cstd; } else break; } ident: tk->t = TKIDENT; tk->s = intern(s); + return 1; } static int @@ -174,7 +176,7 @@ parsenumlit(uvlong *outi, double *outf, const struct token *tk, bool ispp) static uvlong max4typ[TYUVLONG-TYINT+1]; uvlong n = 0; int base = 10, nsx; - bool dec, u = 0, c99 = ccopt.cstd >= STDC99; + bool dec, u = 0, longlongok = ccopt.cstd >= STDC99 || !ccopt.pedant; enum typetag ty = 0; const char *sx; /*suffix*/ char c; @@ -209,13 +211,13 @@ parsenumlit(uvlong *outi, double *outf, const struct token *tk, bool ispp) if (nsx == 1) /* 'u' */ {} else if ((sx[1]|32) == 'l') { if (nsx == 2) /* 'ul' */ goto L; - if (c99 && sx[1] == sx[2] && nsx == 3) /* 'ull' */ goto LL; + if (sx[1] == sx[2] && nsx == 3) /* 'ull' */ goto LL; return 0; } else return 0; } else if ((sx[0]|32) == 'l') { if (nsx == 1) /* 'l' */ goto L; if ((sx[1]|32) == 'u' && nsx == 2) /* 'lu' */ { u=1; goto L; } - if (c99 && sx[1] == sx[0]) { + if (sx[1] == sx[0]) { if (nsx == 2) /* 'll' */ goto LL; if ((sx[2]|32) == 'u' && nsx == 3) /* 'llu' */ { u=1; goto LL; } } @@ -229,8 +231,8 @@ parsenumlit(uvlong *outi, double *outf, const struct token *tk, bool ispp) if (u || !dec) I(TYUINT) L: I(TYLONG) - if (u || !dec || !c99) I(TYULONG) - if (c99) { + if (u || !dec || !longlongok) I(TYULONG) + if (longlongok) { LL: I(TYVLONG) if (u || !dec) I(TYUVLONG) @@ -247,6 +249,8 @@ parsenumlit(uvlong *outi, double *outf, const struct token *tk, bool ispp) if (u) return TYUVLONG; else if (n <= max4typ[TYVLONG-TYINT]) return TYVLONG; } + if (ty >= TYVLONG && !longlongok) + warn(&tk->span, "'long long' in %M is an extension"); return ty; } } @@ -482,7 +486,9 @@ Begin: tmp[n++] = next(pr); } tmp[n] = 0; - identkeyword(tk, tmp, n); + if (!identkeyword(tk, tmp, n)) + warn(&(struct span) {{ idx, pr->chridx - idx, pr->fileid }}, + "%'tk in %M is an extension", tk); goto End; } } diff --git a/main.c b/main.c index 2404fd5..d56cd50 100644 --- a/main.c +++ b/main.c @@ -33,12 +33,14 @@ optparse(const char **file, const char **targ, char **args) continue; } if ((x = optval(arg, "std"))) { - if (!strcmp(x, "c89")) ccopt.cstd = STDC89; + if (!strcmp(x, "c89") || !strcmp(x, "c90")) ccopt.cstd = STDC89; else if (!strcmp(x, "c99")) ccopt.cstd = STDC99; else if (!strcmp(x, "c11")) ccopt.cstd = STDC11; else if (!strcmp(x, "c2x")) ccopt.cstd = STDC23; else if (!strcmp(x, "c23")) ccopt.cstd = STDC23; else goto Bad; + } else if (!strcmp(arg, "pedantic")) { + ccopt.pedant = 1; } else Bad: warn(NULL, "invalid option: %'s", arg-1); } } @@ -61,6 +63,7 @@ main(int argc, char **argv) atexit(flushstd); detectcolor(); + ccopt.cstd = STDC99; /* C99 by default */ optparse(&file, &targ, argv); if (!file) { efmt("usage: %s [options] \n", *argv); diff --git a/parse.c b/parse.c index c33d162..2fc26be 100644 --- a/parse.c +++ b/parse.c @@ -602,7 +602,7 @@ callexpr(struct parser *pr, const struct span *span_, const struct expr *callee) ty = mkfntype(mktype(TYINT), 0, NULL, NULL, /* kandr */ 1, 0), .scls = SCEXTERN, .span = callee->span, .name = name }; - (ccopt.cstd > STDC89 ? error : warn)(&callee->span, "call to undeclared function '%s'", name); + warn(&callee->span, "call to undeclared function '%s'", name); ((struct expr *)callee)->sym = putdecl(pr, &decl); td = &typedata[ty.dat]; } @@ -1816,7 +1816,7 @@ function(struct parser *pr, struct function *fn, const char **pnames, const stru } } putdecl(pr, &arg); - } else { + } else if (ccopt.cstd < STDC23) { warn(&pspans[i], "missing name of parameter #%d", i+1); } } @@ -1873,6 +1873,15 @@ buildagg(struct parser *pr, enum typetag tt, const char *name, int id) uint siz = typesize(decl.ty); uint off = isunion ? 0 : alignup(td.siz, align); struct namedfield f = { decl.name, { decl.ty, off, .qual = decl.qual }}; + if (!decl.name) { + if (!isagg(decl.ty) || ttypenames[typedata[decl.ty.dat].id]) { + warn(&decl.span, "declaration does not declare anything"); + continue; + } else if (ccopt.cstd < STDC11 && ccopt.pedant) { + warn(&decl.span, "anonymous %s in %M is an extension", + decl.ty.t == TYUNION ? "union" : "struct"); + } + } vpush(&fld, f); td.anyconst |= decl.qual & QCONST; if (isagg(decl.ty)) { @@ -1888,6 +1897,8 @@ buildagg(struct parser *pr, enum typetag tt, const char *name, int id) } } while (st.more); } + if (td.flexi && ccopt.cstd < STDC99 && ccopt.pedant) + warn(&flexspan, "flexible array member in %M is an extension"); if (fld.n == 0) { struct namedfield dummy = { "", { mktype(TYCHAR), 0 }}; error(&tk.span, "%s cannot have zero members", tag); @@ -1923,7 +1934,7 @@ inttyminmax(vlong *min, uvlong *max, enum typetag tt) * prefers to use unsigned types when possible). should add support for -fshort-enums */ static union type -buildenum(struct parser *pr, const char *name) +buildenum(struct parser *pr, const char *name, const struct span *span) { struct token tk; vlong tymin, minv = 0; @@ -1932,6 +1943,7 @@ buildenum(struct parser *pr, const char *name) union type ty = mktype(td.backing); struct span maxvspan; vlong iota = 0; + bool somelonglong = 0; inttyminmax(&tymin, &tymax, td.backing); while (!match(pr, &tk, '}')) { @@ -1954,6 +1966,7 @@ buildenum(struct parser *pr, const char *name) } while (issigned(ty) ? (iota > (vlong)tymax || iota < tymin) : iota > tymax) inttyminmax(&tymin, &tymax, ++ty.t); + somelonglong |= ty.t >= TYVLONG; if ((isunsigned(ty) || iota > 0) && iota > maxv) maxv = iota, maxvspan = tk.span; else if (issigned(ty) && iota < minv) @@ -1980,9 +1993,12 @@ buildenum(struct parser *pr, const char *name) } } if (!td.backing) { - td.backing = TYVLONG; - warn(&maxvspan, "some enumerators are too large for the enum's backing type (%ty)", mktype(td.backing)); + td.backing = !somelonglong && ccopt.cstd == STDC89 && ccopt.pedant ? TYLONG : TYVLONG; + warn(&maxvspan, "enumerators exceed range of enum's backing type (%ty)", mktype(td.backing)); } + if (td.backing >= TYVLONG && !somelonglong && ccopt.cstd == STDC89 && ccopt.pedant) + warn(span, "enum backing type is '%ty' in %M", mktype(td.backing)); + ty = mktagtype(name, &td); ty.backing = td.backing; return ty; @@ -2137,6 +2153,11 @@ declspec(struct declstate *st, struct parser *pr) default: if (!span.ex.len) span.ex = tk.span.ex; goto End; + case TKW_BitInt: case TKW_Complex: + case TKW_Decimal128: case TKW_Decimal32: + case TKW_Decimal64: case TKW_Imaginary: + error(&tk.span, "%'tk is unsupported", &tk); + arith = arith ? arith : KINT; } if (!span.ex.len) span.ex = tk.span.ex; joinspan(&span.ex, tk.span.ex); @@ -2148,6 +2169,7 @@ End: /* combining arith type specifiers and other types */ Bad: error(&span, "invalid declaration specifier"); + st->base = mktype(TYINT); } else if (!st->base.t && arith) { enum typetag t; ioflush(&bstderr); @@ -2155,9 +2177,10 @@ End: t = TYFLOAT; else if (arith == KDOUBLE) t = TYDOUBLE; - else if (arith == (KLONG | KDOUBLE)) + else if (arith == (KLONG | KDOUBLE)) { t = TYLDOUBLE; - else if (arith == KBOOL) + error(&span, "`long double' is unsupported"); + } else if (arith == KBOOL) t = TYBOOL; else if (arith == KCHAR) t = TYCHAR; @@ -2183,8 +2206,8 @@ End: t = TYUVLONG; else goto Bad; - st->base = mktype(t); - } else if (!st->base.t && ccopt.cstd < STDC99) { + st->base = mktype(t ? t : TYINT); + } else if (!st->base.t && ccopt.cstd < STDC23) { warn(&span, "type implicitly declared as int"); st->base = mktype(TYINT); } else if (!st->base.t) diff --git a/test.c b/test.c index 92ab2f2..40b59e6 100644 --- a/test.c +++ b/test.c @@ -80,13 +80,18 @@ enum ball { X = 2147483647, Y, Z, - W = ~0ul + W = ~0ull }; enum ball x; -main(t) { - putc(t + 1, t + 2); +_Bool t(int t) +{ + return t; } +struct f{ + union { int x,y;} ; + char flex[]; +}; // -- cgit v1.2.3