aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Forney <mforney@mforney.org>2019-02-18 12:34:25 -0800
committerMichael Forney <mforney@mforney.org>2019-02-18 12:48:38 -0800
commit9f964b728151066dd37dd80269ed23ea4b4cdeab (patch)
tree4dcde4880c175d6b2d1ef4903eaf6b746cda8836
parent27e77f6ca6872c8d332c2e153773ca226d69fb64 (diff)
downloadcproc-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.c1
-rw-r--r--tests/common-real-int-sign.c4
-rw-r--r--tests/common-real-int-sign.qbe14
-rw-r--r--type.c6
-rw-r--r--type.h1
5 files changed, 25 insertions, 1 deletions
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,