From 9f964b728151066dd37dd80269ed23ea4b4cdeab Mon Sep 17 00:00:00 2001 From: Michael Forney Date: Mon, 18 Feb 2019 12:34:25 -0800 Subject: Fix compatible check for basic types This check was only supposed to return true for enum types and their corresponding integer type. However, it had the side effect of making 'int' compatible with 'unsigned'. To fix this, introduce a new basic type kind for enums with the same rank as 'int', that is only compatible with itself and the 'int' type with the matching sign. Thanks to Andrew Chambers for the bug report. --- decl.c | 1 + tests/common-real-int-sign.c | 4 ++++ tests/common-real-int-sign.qbe | 14 ++++++++++++++ type.c | 6 +++++- type.h | 1 + 5 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 tests/common-real-int-sign.c create mode 100644 tests/common-real-int-sign.qbe diff --git a/decl.c b/decl.c index f9640fc..67bb361 100644 --- a/decl.c +++ b/decl.c @@ -185,6 +185,7 @@ tagspec(struct scope *s) t = mktype(kind, NULL); if (kind == TYPEBASIC) { *t = typeint; + t->basic.kind = BASICENUM; } else { t->repr = &i64; // XXX t->size = 0; diff --git a/tests/common-real-int-sign.c b/tests/common-real-int-sign.c new file mode 100644 index 0000000..d67c301 --- /dev/null +++ b/tests/common-real-int-sign.c @@ -0,0 +1,4 @@ +int main(void) { + unsigned x = -1; + return 0 > x; +} diff --git a/tests/common-real-int-sign.qbe b/tests/common-real-int-sign.qbe new file mode 100644 index 0000000..589c72e --- /dev/null +++ b/tests/common-real-int-sign.qbe @@ -0,0 +1,14 @@ +export +function w $main() { +@start.1 + %.1 =l alloc4 4 +@body.2 + %.2 =l add %.1, 0 + %.3 =w sub 0, 1 + %.4 =w copy %.3 + storew %.4, %.2 + %.5 =w copy 0 + %.6 =w loaduw %.1 + %.7 =w cugtw %.5, %.6 + ret %.7 +} diff --git a/type.c b/type.c index 79c2454..224153b 100644 --- a/type.c +++ b/type.c @@ -142,6 +142,7 @@ typerank(struct type *t) case BASICBOOL: return 1; case BASICCHAR: return 2; case BASICSHORT: return 3; + case BASICENUM: case BASICINT: return 4; case BASICLONG: return 5; case BASICLONGLONG: return 6; @@ -162,9 +163,12 @@ typecompatible(struct type *t1, struct type *t2) return false; switch (t1->kind) { case TYPEBASIC: + if (t1->basic.issigned != t2->basic.issigned) + return false; /* enum types are compatible with 'int', but not with each other (unless they are the same type) */ - return t1->basic.kind == t2->basic.kind && (t1 == &typeint || t2 == &typeint); + return t1->basic.kind == BASICENUM && t2->basic.kind == BASICINT || + t1->basic.kind == BASICINT && t2->basic.kind == BASICENUM; case TYPEQUALIFIED: if (t1->qualified.kind != t2->qualified.kind) return false; diff --git a/type.h b/type.h index d985a4a..0da444b 100644 --- a/type.h +++ b/type.h @@ -68,6 +68,7 @@ struct type { BASICCHAR, BASICSHORT, BASICINT, + BASICENUM, BASICLONG, BASICLONGLONG, BASICFLOAT, -- cgit v1.2.3