commit a63b11584c3d43ddcc2080dca8ce692aa56c3d52
parent 624848780072de338c258596833708934bed9204
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date: Thu, 7 Jan 2016 16:52:45 +0100
Implement type rules in ternary operator
The rules of ths standard about the types implied
in the ternary operator are complex, and I was not
matching them. This patch breaks the test003,
because optimization of ternary is removed.
Diffstat:
M | cc1/expr.c | | | 125 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------ |
1 file changed, 87 insertions(+), 38 deletions(-)
diff --git a/cc1/expr.c b/cc1/expr.c
@@ -79,27 +79,98 @@ promote(Node *np)
}
static void
-typeconv(Node **p1, Node **p2)
+arithconv(Node **p1, Node **p2)
{
+ int n, to = 0, s1, s2;
+ unsigned r1, r2;
Type *tp1, *tp2;
Node *np1, *np2;
- int n;
+ struct limits *lp1, *lp2;
np1 = promote(*p1);
np2 = promote(*p2);
tp1 = np1->type;
tp2 = np2->type;
- if (tp1 != tp2) {
- if ((n = tp1->n.rank - tp2->n.rank) > 0)
- np2 = convert(np2, tp1, 1);
- else if (n < 0)
- np1 = convert(np1, tp2, 1);
+
+ if (tp1 == tp2)
+ goto set_p1_p2;
+
+ s1 = tp1->sign, r1 = tp1->n.rank, lp1 = getlimits(tp1);
+ s2 = tp2->sign, r2 = tp2->n.rank, lp2 = getlimits(tp2);
+
+ if (s1 == s2 || tp1->op == FLOAT || tp2->op == FLOAT) {
+ to = r1 - r2;
+ } else if (!s1) {
+ if (r1 >= r2 || lp1->max.i >= lp2->max.i)
+ to = 1;
+ else
+ to = -1;
+ } else {
+ if (r2 >= r1 || lp2->max.i >= lp1->max.i)
+ to = -1;
+ else
+ to = 1;
}
+
+ if (to > 0)
+ np2 = convert(np2, tp1, 1);
+ else if (to < 0)
+ np1 = convert(np1, tp2, 1);
+
+set_p1_p2:
*p1 = np1;
*p2 = np2;
}
+static Node *
+chkternary(Node *ifyes, Node *ifno)
+{
+ int arithy = 0, aithn = 0;
+ Type *tyes, *tno;
+
+ tyes = ifyes->type, tno = ifno->type;
+
+ switch (tyes->op) {
+ case ENUM:
+ case INT:
+ case FLOAT:
+ switch (tno->op) {
+ case ENUM:
+ case INT:
+ case FLOAT:
+ arithconv(&ifyes, &ifno);
+ break;
+ default:
+ goto wrong_type;
+ }
+ break;
+ case ARY:
+ case FTN:
+ ifyes = decay(ifyes);
+ tyes = ifyes->type;
+ ifno = decay(ifno);
+ tno = ifno->type;
+ case PTR:
+ if ((ifno = convert(ifno, tyes, 0)) == NULL)
+ goto wrong_type;
+ break;
+ case VOID:
+ case STRUCT:
+ case UNION:
+ if (!eqtype(tyes, tno))
+ goto wrong_type;
+ break;
+ default:
+ abort();
+ }
+ return node(OCOLON, ifyes->type, ifyes, ifno);
+
+wrong_type:
+ errorp("type mismatch in conditional expression");
+ return node(OCOLON, ifyes->type, ifyes, ifyes);
+}
+
static void
chklvalue(Node *np)
{
@@ -135,7 +206,7 @@ integerop(char op, Node *lp, Node *rp)
{
if (BTYPE(lp) != INT || BTYPE(rp) != INT)
error("operator requires integer operands");
- typeconv(&lp, &rp);
+ arithconv(&lp, &rp);
return simplify(op, lp->type, lp, rp);
}
@@ -181,7 +252,7 @@ convert(Node *np, Type *newtp, char iscast)
case FLOAT:
switch (newtp->op) {
case PTR:
- if (!iscast || oldtp->op == FLOAT)
+ if (oldtp->op == FLOAT || !cmpnode(np, 0) && !iscast)
return NULL;
/* PASSTHROUGH */
case INT:
@@ -203,8 +274,7 @@ convert(Node *np, Type *newtp, char iscast)
break;
case PTR:
if (iscast ||
- newtp == pvoidtype ||
- oldtp == pvoidtype) {
+ newtp == pvoidtype || oldtp == pvoidtype) {
/* TODO:
* we assume conversion between pointers
* do not need any operation, but due to
@@ -260,7 +330,7 @@ arithmetic(char op, Node *lp, Node *rp)
switch (BTYPE(rp)) {
case INT:
case FLOAT:
- typeconv(&lp, &rp);
+ arithconv(&lp, &rp);
break;
case PTR:
if (op == OADD || op == OSUB)
@@ -309,7 +379,7 @@ compare(char op, Node *lp, Node *rp)
switch (BTYPE(rp)) {
case INT:
case FLOAT:
- typeconv(&lp, &rp);
+ arithconv(&lp, &rp);
break;
case PTR:
return pcompare(op, rp, lp);
@@ -436,15 +506,7 @@ array(Node *lp, Node *rp)
static Node *
assignop(char op, Node *lp, Node *rp)
{
- int force = 0;
- Type *tp = lp->type;
-
- rp = decay(rp);
- if (BTYPE(rp) == INT && tp->op == PTR && cmpnode(rp, 0)) {
- tp = pvoidtype;
- force = 1;
- }
- if ((rp = convert(rp, tp, force)) == NULL) {
+ if ((rp = convert(decay(rp), lp->type, 0)) == NULL) {
errorp((op == OINIT) ?
"incorrect initiliazer" :
"incompatible types when assigning");
@@ -937,23 +999,10 @@ ternary(void)
Node *ifyes, *ifno, *np;
cond = exp2cond(cond, 0);
- ifyes = promote(expr());
+ ifyes = expr();
expect(':');
- ifno = promote(ternary());
- typeconv(&ifyes, &ifno);
- if (cond->constant) {
- TINT i = cond->sym->u.i;
-
- freetree(cond);
- if (i == 0) {
- freetree(ifyes);
- return ifno;
- } else {
- freetree(ifno);
- return ifyes;
- }
- }
- np = node(OCOLON, ifyes->type, ifyes, ifno);
+ ifno = ternary();
+ np = chkternary(ifyes, ifno);
cond = node(OASK, np->type, cond, np);
}
return cond;