diff options
author | Michael Forney <mforney@mforney.org> | 2019-02-18 12:34:25 -0800 |
---|---|---|
committer | Michael Forney <mforney@mforney.org> | 2019-02-18 12:48:38 -0800 |
commit | 9f964b728151066dd37dd80269ed23ea4b4cdeab (patch) | |
tree | 4dcde4880c175d6b2d1ef4903eaf6b746cda8836 | |
parent | 27e77f6ca6872c8d332c2e153773ca226d69fb64 (diff) | |
download | cproc-9f964b728151066dd37dd80269ed23ea4b4cdeab.tar.xz |
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.
-rw-r--r-- | decl.c | 1 | ||||
-rw-r--r-- | tests/common-real-int-sign.c | 4 | ||||
-rw-r--r-- | tests/common-real-int-sign.qbe | 14 | ||||
-rw-r--r-- | type.c | 6 | ||||
-rw-r--r-- | type.h | 1 |
5 files changed, 25 insertions, 1 deletions
@@ -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 +} @@ -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; @@ -68,6 +68,7 @@ struct type { BASICCHAR, BASICSHORT, BASICINT, + BASICENUM, BASICLONG, BASICLONGLONG, BASICFLOAT, |