~mcf/cproc

38b1d570ac9f35af9b58e7ff33d61698b83384ff — Michael Forney a month ago 662a5dd
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.
3 files changed, 45 insertions(+), 59 deletions(-)

M cc.h
M decl.c
M type.c
M cc.h => cc.h +1 -1
@@ 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 {

M decl.c => decl.c +36 -49
@@ 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;

M type.c => type.c +8 -9
@@ 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: