aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tccgen.c18
-rw-r--r--tests/tests2/93_integer_promotion.c71
-rw-r--r--tests/tests2/93_integer_promotion.expect46
3 files changed, 126 insertions, 9 deletions
diff --git a/tccgen.c b/tccgen.c
index e1017f5..00f6aa3 100644
--- a/tccgen.c
+++ b/tccgen.c
@@ -2086,23 +2086,23 @@ redo:
goto std_op;
} else if (op == TOK_SHR || op == TOK_SAR || op == TOK_SHL) {
t = bt1 == VT_LLONG ? VT_LLONG : VT_INT;
- if ((t1 & (VT_BTYPE | VT_UNSIGNED)) == (t | VT_UNSIGNED))
+ if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (t | VT_UNSIGNED))
t |= VT_UNSIGNED;
goto std_op;
} else if (bt1 == VT_LLONG || bt2 == VT_LLONG) {
/* cast to biggest op */
t = VT_LLONG;
/* convert to unsigned if it does not fit in a long long */
- if ((t1 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED) ||
- (t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED))
+ if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED) ||
+ (t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED))
t |= VT_UNSIGNED;
goto std_op;
} else {
/* integer operations */
t = VT_INT;
/* convert to unsigned if it does not fit in an integer */
- if ((t1 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED) ||
- (t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED))
+ if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED) ||
+ (t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED))
t |= VT_UNSIGNED;
std_op:
/* XXX: currently, some unsigned operations are explicit, so
@@ -5198,8 +5198,8 @@ static void expr_cond(void)
/* cast to biggest op */
type.t = VT_LLONG;
/* convert to unsigned if it does not fit in a long long */
- if ((t1 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED) ||
- (t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_LLONG | VT_UNSIGNED))
+ if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED) ||
+ (t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_LLONG | VT_UNSIGNED))
type.t |= VT_UNSIGNED;
} else if (bt1 == VT_PTR || bt2 == VT_PTR) {
/* If one is a null ptr constant the result type
@@ -5225,8 +5225,8 @@ static void expr_cond(void)
/* integer operations */
type.t = VT_INT;
/* convert to unsigned if it does not fit in an integer */
- if ((t1 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED) ||
- (t2 & (VT_BTYPE | VT_UNSIGNED)) == (VT_INT | VT_UNSIGNED))
+ if ((t1 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED) ||
+ (t2 & (VT_BTYPE | VT_UNSIGNED | VT_BITFIELD)) == (VT_INT | VT_UNSIGNED))
type.t |= VT_UNSIGNED;
}
/* keep structs lvalue by transforming `(expr ? a : b)` to `*(expr ? &a : &b)` so
diff --git a/tests/tests2/93_integer_promotion.c b/tests/tests2/93_integer_promotion.c
new file mode 100644
index 0000000..a1176fc
--- /dev/null
+++ b/tests/tests2/93_integer_promotion.c
@@ -0,0 +1,71 @@
+/* integer promotion */
+
+int printf(const char*, ...);
+#define promote(s) printf(" %ssigned : %s\n", (s) - 100 < 0 ? " " : "un", #s);
+
+int main (void)
+{
+ struct {
+ unsigned ub:3;
+ unsigned u:32;
+ unsigned long long ullb:35;
+ unsigned long long ull:64;
+ unsigned char c;
+ } s = { 1, 1, 1 };
+
+ promote(s.ub);
+ promote(s.u);
+ promote(s.ullb);
+ promote(s.ull);
+ promote(s.c);
+ printf("\n");
+
+ promote((1 ? s.ub : 1));
+ promote((1 ? s.u : 1));
+ promote((1 ? s.ullb : 1));
+ promote((1 ? s.ull : 1));
+ promote((1 ? s.c : 1));
+ printf("\n");
+
+ promote(s.ub << 1);
+ promote(s.u << 1);
+ promote(s.ullb << 1);
+ promote(s.ull << 1);
+ promote(s.c << 1);
+ printf("\n");
+
+ promote(+s.ub);
+ promote(+s.u);
+ promote(+s.ullb);
+ promote(+s.ull);
+ promote(+s.c);
+ printf("\n");
+
+ promote(-s.ub);
+ promote(-s.u);
+ promote(-s.ullb);
+ promote(-s.ull);
+ promote(-s.c);
+ printf("\n");
+
+ promote(~s.ub);
+ promote(~s.u);
+ promote(~s.ullb);
+ promote(~s.ull);
+ promote(~s.c);
+ printf("\n");
+
+ promote(!s.ub);
+ promote(!s.u);
+ promote(!s.ullb);
+ promote(!s.ull);
+ promote(!s.c);
+ printf("\n");
+
+ promote(+(unsigned)s.ub);
+ promote(-(unsigned)s.ub);
+ promote(~(unsigned)s.ub);
+ promote(!(unsigned)s.ub);
+
+ return 0;
+}
diff --git a/tests/tests2/93_integer_promotion.expect b/tests/tests2/93_integer_promotion.expect
new file mode 100644
index 0000000..34b9c14
--- /dev/null
+++ b/tests/tests2/93_integer_promotion.expect
@@ -0,0 +1,46 @@
+ signed : s.ub
+ unsigned : s.u
+ signed : s.ullb
+ unsigned : s.ull
+ signed : s.c
+
+ signed : (1 ? s.ub : 1)
+ unsigned : (1 ? s.u : 1)
+ signed : (1 ? s.ullb : 1)
+ unsigned : (1 ? s.ull : 1)
+ signed : (1 ? s.c : 1)
+
+ signed : s.ub << 1
+ unsigned : s.u << 1
+ signed : s.ullb << 1
+ unsigned : s.ull << 1
+ signed : s.c << 1
+
+ signed : +s.ub
+ unsigned : +s.u
+ signed : +s.ullb
+ unsigned : +s.ull
+ signed : +s.c
+
+ signed : -s.ub
+ unsigned : -s.u
+ signed : -s.ullb
+ unsigned : -s.ull
+ signed : -s.c
+
+ signed : ~s.ub
+ unsigned : ~s.u
+ signed : ~s.ullb
+ unsigned : ~s.ull
+ signed : ~s.c
+
+ signed : !s.ub
+ signed : !s.u
+ signed : !s.ullb
+ signed : !s.ull
+ signed : !s.c
+
+ unsigned : +(unsigned)s.ub
+ unsigned : -(unsigned)s.ub
+ unsigned : ~(unsigned)s.ub
+ signed : !(unsigned)s.ub