diff options
author | Michael Forney <mforney@mforney.org> | 2024-03-16 14:22:43 -0700 |
---|---|---|
committer | Michael Forney <mforney@mforney.org> | 2024-03-16 14:41:19 -0700 |
commit | 8bed97beaea3839369a947ea741aa083e76ca014 (patch) | |
tree | aac7e8be8be1a05ff9ee2bc9a5ecefc224221669 | |
parent | 773bae1fe954fd578a8360c01ca83675bba9e6b4 (diff) |
Store enum underlying type in base field
This will facilitate supporting underlying types other than int or
unsigned, possible in C23.
References: https://todo.sr.ht/~mcf/cproc/64
-rw-r--r-- | decl.c | 11 | ||||
-rw-r--r-- | type.c | 15 |
2 files changed, 15 insertions, 11 deletions
@@ -177,9 +177,8 @@ tagspec(struct scope *s) error(&tok.loc, "redeclaration of tag '%s' with different kind", tag); } else { if (kind == TYPEENUM) { - t = xmalloc(sizeof(*t)); - *t = typeuint; - t->kind = kind; + t = mktype(kind, PROPSCALAR|PROPARITH|PROPREAL|PROPINT); + t->base = &typeuint; } else { t = mktype(kind, 0); t->size = 0; @@ -223,7 +222,7 @@ tagspec(struct scope *s) if (e->type->u.basic.issigned && i >= 1ull << 63) { if (i < -1ull << 31) goto invalid; - t->u.basic.issigned = true; + t->base = &typeint; } else if (i >= 1ull << 32) { goto invalid; } @@ -237,13 +236,15 @@ tagspec(struct scope *s) large = true; d->type = &typeuint; } - if (large && t->u.basic.issigned) + if (large && t->base->u.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"); + t->size = t->base->size; + t->align = t->base->align; t->incomplete = false; } @@ -91,12 +91,13 @@ mkarraytype(struct type *base, enum typequal qual, unsigned long long len) static int typerank(struct type *t) { + if (t->kind == TYPEENUM) + t = t->base; assert(t->prop & PROPINT); switch (t->kind) { 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; @@ -114,11 +115,13 @@ typecompatible(struct type *t1, struct type *t2) if (t1 == t2) return true; 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->u.basic.issigned == t2->u.basic.issigned; + /* + enum types are compatible with their underlying + type, but not with each other (unless they are the + same type) + */ + return t1->kind == TYPEENUM && t2 == t1->base || + t2->kind == TYPEENUM && t1 == t2->base; } switch (t1->kind) { case TYPEPOINTER: |