diff options
author | Michael Forney <mforney@mforney.org> | 2020-06-03 03:22:11 -0700 |
---|---|---|
committer | Michael Forney <mforney@mforney.org> | 2020-06-03 03:22:11 -0700 |
commit | 38b1d570ac9f35af9b58e7ff33d61698b83384ff (patch) | |
tree | 2a8a03923d5e786205658fdae923f77ce4c8b835 | |
parent | 662a5dd71ed37fd8938f0da4f64149bcf07ba154 (diff) |
Revert "decl: Allow out-of-range enum constants when they don't change type"
This reverts commit 6229709b8ae21d7722fef48ad8a9f2f10b900030.
I still don't understand how out-of-range enum constants are supposed
to work.
-rw-r--r-- | cc.h | 2 | ||||
-rw-r--r-- | decl.c | 85 | ||||
-rw-r--r-- | type.c | 17 |
3 files changed, 45 insertions, 59 deletions
@@ -147,6 +147,7 @@ enum typekind { TYPECHAR, TYPESHORT, TYPEINT, + TYPEENUM, TYPELONG, TYPELLONG, TYPEFLOAT, @@ -171,7 +172,6 @@ enum typeprop { PROPAGGR = 1<<6, PROPDERIVED = 1<<7, PROPFLOAT = 1<<8, - PROPENUM = 1<<9, }; struct param { @@ -1,5 +1,4 @@ #include <assert.h> -#include <limits.h> #include <inttypes.h> #include <stdbool.h> #include <stddef.h> @@ -144,35 +143,22 @@ funcspec(enum funcspec *fs) static void structdecl(struct scope *, struct structbuilder *); -static unsigned long long -intmax(struct type *t) -{ - return -1ull >> sizeof(unsigned long long) * CHAR_BIT - t->size * 8 + t->basic.issigned; -} - -static bool -inrange(struct type *t, unsigned long long v, bool sign) -{ - if (sign && v >= 1ull << 63) - return t->basic.issigned && v >= -1ull << t->size * 8 - 1; - return v <= intmax(t); -} - static struct type * tagspec(struct scope *s) { - struct type *t, *et, *ct; + struct type *t; char *tag, *name; enum typekind kind; struct decl *d; struct expr *e; struct structbuilder b; uint64_t i; + bool large; switch (tok.kind) { case TSTRUCT: kind = TYPESTRUCT; break; case TUNION: kind = TYPEUNION; break; - case TENUM: kind = TYPEINT; break; + case TENUM: kind = TYPEENUM; break; default: fatal("internal error: unknown tag kind"); } next(); @@ -182,28 +168,30 @@ tagspec(struct scope *s) } else { tag = expect(TIDENT, "or '{' after struct/union"); t = scopegettag(s, tag, false); - if (s->parent && !t && tok.kind != TLBRACE && (kind == TYPEINT || tok.kind != TSEMICOLON)) + if (s->parent && !t && tok.kind != TLBRACE && (kind == TYPEENUM || tok.kind != TSEMICOLON)) t = scopegettag(s->parent, tag, true); } - if (!t) { - t = mktype(kind, PROPOBJECT); - t->size = 0; - t->align = 0; - if (kind == TYPEINT) { - t->prop |= PROPENUM; - t->basic.issigned = false; + if (t) { + if (t->kind != kind) + error(&tok.loc, "redeclaration of tag '%s' with different kind", tag); + } else { + if (kind == TYPEENUM) { + t = xmalloc(sizeof(*t)); + *t = typeuint; + t->kind = kind; } else { + t = mktype(kind, PROPOBJECT); if (kind == TYPESTRUCT) t->prop |= PROPAGGR; t->repr = &i64; // XXX + t->size = 0; + t->align = 0; t->structunion.tag = tag; t->structunion.members = NULL; } t->incomplete = true; if (tag) scopeputtag(s, tag, t); - } else if (t->kind != kind && (kind != TYPEINT || t->prop & PROPENUM)) { - error(&tok.loc, "redeclaration of tag '%s' with different kind", tag); } if (tok.kind != TLBRACE) return t; @@ -222,9 +210,8 @@ tagspec(struct scope *s) t->size = ALIGNUP(t->size, t->align); t->incomplete = false; break; - case TYPEINT: - et = NULL; - ct = &typeint; + case TYPEENUM: + large = false; for (i = 0; tok.kind == TIDENT; ++i) { name = tok.lit; next(); @@ -233,31 +220,31 @@ tagspec(struct scope *s) if (e->kind != EXPRCONST || !(e->type->prop & PROPINT)) error(&tok.loc, "expected integer constant expression"); i = e->constant.i; - t->basic.issigned |= e->type->basic.issigned && i >= 1ull << 63; - if (inrange(&typeint, i, e->type->basic.issigned)) - ct = &typeint; - else if (et && !typecompatible(et, e->type)) - error(&tok.loc, "enumerator '%s' value is outside the range of 'int'", name); - else - ct = et = e->type; - } else if (i - 1 == intmax(ct)) { - /* the constant is outside the range of the type of the previous enumerator */ - error(&tok.loc, "enumerator '%s' value overflow", name); + if (e->type->basic.issigned && i >= 1ull << 63) { + if (i < -1ull << 31) + goto invalid; + t->basic.issigned = true; + } else if (i >= 1ull << 32) { + goto invalid; + } + } else if (i == 1ull << 32) { + invalid: + error(&tok.loc, "enumerator '%s' value cannot be represented as 'int' or 'unsigned int'", name); } - d = mkdecl(DECLCONST, ct, QUALNONE, LINKNONE); - d->value = mkintconst(ct->repr, i); + d = mkdecl(DECLCONST, &typeint, QUALNONE, LINKNONE); + d->value = mkintconst(t->repr, i); + if (i >= 1ull << 31 && i < 1ull << 63) { + large = true; + d->type = &typeuint; + } + if (large && t->basic.issigned) + error(&tok.loc, "neither 'int' nor 'unsigned' can represent all enumerator values"); scopeputdecl(s, name, d); if (!consume(TCOMMA)) break; } expect(TRBRACE, "to close enum specifier"); - if (!et) - et = t->basic.issigned ? &typeint : &typeuint; - else if (t->basic.issigned && !et->basic.issigned) - error(&tok.loc, "enumerator with range outside of 'int' is not compatible with enum type"); - *t = *et; - t->prop |= PROPENUM; - break; + t->incomplete = false; } return t; @@ -106,6 +106,7 @@ typerank(struct type *t) case TYPEBOOL: return 1; case TYPECHAR: return 2; case TYPESHORT: return 3; + case TYPEENUM: case TYPEINT: return 4; case TYPELONG: return 5; case TYPELLONG: return 6; @@ -122,16 +123,14 @@ typecompatible(struct type *t1, struct type *t2) if (t1 == t2) return true; - if (t1->kind != t2->kind) - return false; - switch (t1->kind) { - case TYPEINT: - case TYPELONG: - case TYPELLONG: - /* enum types are compatible with some basic integer - type, but not with other enum types */ - return (t1->prop & PROPENUM) != (t2->prop & PROPENUM) && + if (t1->kind != t2->kind) { + /* enum types are compatible with 'int', but not with + each other (unless they are the same type) */ + return (t1->kind == TYPEENUM && t2->kind == TYPEINT || + t1->kind == TYPEINT && t2->kind == TYPEENUM) && t1->basic.issigned == t2->basic.issigned; + } + switch (t1->kind) { case TYPEPOINTER: goto derived; case TYPEARRAY: |