lint: additional type tests in expressions
authordick <none@none>
Thu, 29 Sep 1988 15:24:02 +0000 (15:24 +0000)
committerdick <none@none>
Thu, 29 Sep 1988 15:24:02 +0000 (15:24 +0000)
lang/cem/cemcom/arith.c
lang/cem/cemcom/ch7.c
lang/cem/cemcom/ch7bin.c
lang/cem/cemcom/dumpidf.c
lang/cem/cemcom/expr.c
lang/cem/cemcom/expr.str
lang/cem/cemcom/l_brace.str
lang/cem/cemcom/l_lint.c
lang/cem/cemcom/l_misc.c
lang/cem/cemcom/l_states.c
lang/cem/cemcom/statement.g

index b8928a1..04f9da6 100644 (file)
@@ -12,6 +12,7 @@
 */
 
 #include       <alloc.h>
+#include       "lint.h"
 #include       "nofloat.h"
 #include       "nobitfield.h"
 #include       "idf.h"
@@ -163,7 +164,9 @@ any2arith(expp, oper)
                else
                        expr_warning(*expp, "%s on enum", symbol2str(oper));
 #endif NOROPTION
+#ifndef        LINT
                int2int(expp, int_type);
+#endif LINT
                break;
 #ifndef        NOFLOAT
        case FLOAT:
@@ -420,53 +423,6 @@ is_test_op(oper)
        /*NOTREACHED*/
 }
 
-#ifdef ____
-int
-is_arith_op(oper)
-{
-       switch (oper) {
-       case '*':
-       case '/':
-       case '%':
-       case '+':
-       case '-':
-       case LEFT:
-       case RIGHT:
-       case '&':
-       case '^':
-       case '|':
-               return 1;
-       default:
-               return 0;
-       }
-}
-
-int
-is_asgn_op(oper)
-{
-       switch (oper) {
-       case '=':
-       case PLUSAB:
-       case MINAB:
-       case TIMESAB:
-       case DIVAB:
-       case MODAB:
-       case LEFTAB:
-       case RIGHTAB:
-       case ANDAB:
-       case ORAB:
-       case XORAB:
-       case PLUSPLUS:
-       case POSTINCR:
-       case MINMIN:
-       case POSTDECR:
-               return 1;
-       default:
-               return 0;
-       }
-}
-#endif
-
 any2opnd(expp, oper)
        register struct expr **expp;
 {
index 597debc..bb213c4 100644 (file)
@@ -163,21 +163,26 @@ ch7cast(expp, oper, tp)
        if ((*expp)->ex_class == String)
                string2pointer(*expp);
        oldtp = (*expp)->ex_type;
+
 #ifndef NOBITFIELD
        if (oldtp->tp_fund == FIELD)    {
                field2arith(expp);
                ch7cast(expp, oper, tp);
        }
        else
-       if (tp->tp_fund == FIELD)
+       if (tp->tp_fund == FIELD) {
                ch7cast(expp, oper, tp->tp_up);
+       }
        else
 #endif NOBITFIELD
-       if (oldtp == tp)
-               {}                      /* life is easy */
+       if (oldtp == tp) {
+               /* life is easy */
+       }
        else
-       if (tp->tp_fund == VOID)        /* Easy again */
+       if (tp->tp_fund == VOID) {
+               /* Easy again */
                (*expp)->ex_type = void_type;
+       }
        else
        if (is_arith_type(oldtp) && is_arith_type(tp))  {
                int oldi = is_integral_type(oldtp);
@@ -191,7 +196,14 @@ ch7cast(expp, oper, tp)
                                expr_warning(*expp,
                                        "%s on enums of different types",
                                        symbol2str(oper));
+#ifdef LINT
+                       if (oper == CAST)
+                               (*expp)->ex_type = tp;
+                       else
+                               int2int(expp, tp);
+#else  LINT
                        int2int(expp, tp);
+#endif LINT
                }
 #ifndef NOFLOAT
                else
@@ -200,13 +212,37 @@ ch7cast(expp, oper, tp)
                                expr_warning(*expp,
                                        "conversion of enum to %s\n",
                                        symbol2str(tp->tp_fund));
+#ifdef LINT
+                       if (oper == CAST)
+                               (*expp)->ex_type = tp;
+                       else
+                               int2float(expp, tp);
+#else  LINT
                        int2float(expp, tp);
+#endif LINT
                }
                else
-               if (!oldi && i)
+               if (!oldi && i) {
+#ifdef LINT
+                       if (oper == CAST)
+                               (*expp)->ex_type = tp;
+                       else
+                               float2int(expp, tp);
+#else  LINT
                        float2int(expp, tp);
-               else            /* !oldi && !i */
+#endif LINT
+               }
+               else {
+                       /* !oldi && !i */
+#ifdef LINT
+                       if (oper == CAST)
+                               (*expp)->ex_type = tp;
+                       else
+                               float2float(expp, tp);
+#else  LINT
                        float2float(expp, tp);
+#endif LINT
+               }
 #else NOFLOAT
                else {
                        crash("(ch7cast) floats not implemented\n");
@@ -269,8 +305,10 @@ ch7cast(expp, oper, tp)
                        (*expp)->ex_type = tp;
        }
        else
-       if (oldtp->tp_fund == ERRONEOUS) /* we just won't look */
+       if (oldtp->tp_fund == ERRONEOUS) {
+               /* we just won't look */
                (*expp)->ex_type = tp;  /* brute force */
+       }
        else
        if (oldtp->tp_size == tp->tp_size && oper == CAST)      {
                expr_warning(*expp, "dubious conversion based on equal size");
@@ -321,6 +359,7 @@ ch7asgn(expp, oper, expr)
                struct expr *extmp = intexpr((arith)0, INT);
 
                /* this is really $#@&*%$# ! */
+               /* if you correct this, please correct lint_new_oper() too */
                extmp->ex_lvalue = 1;
                extmp->ex_type = exp->ex_type;
                ch7bin(&extmp, oper, expr);
index a24bee9..c26a89e 100644 (file)
@@ -303,7 +303,7 @@ mk_binop(expp, oper, expr, commutative)
        register struct expr *expr;
 {
        /*      Constructs in *expp the operation indicated by the operands.
-               "commutative" indicates wether "oper" is a commutative
+               "commutative" indicates whether "oper" is a commutative
                operator.
        */
        register struct expr *ex = *expp;
index b07ebc9..cf92c1d 100644 (file)
@@ -254,8 +254,8 @@ type2str(tp)
                sprint(buf, "<NILTYPE>");
                return buf;
        }
-       sprint(buf, "(@%lx, #%ld, &%d) ",
-                       tp, (long)tp->tp_size, tp->tp_align);
+
+       sprint(buf, "%s(#%ld, &%d) ", buf, (long)tp->tp_size, tp->tp_align);
        while (ops)     {
                switch (tp->tp_fund)    {
                case POINTER:
index 21b8815..0b317b4 100644 (file)
@@ -352,6 +352,7 @@ new_oper(tp, e1, oper, e2)
                expr->ex_file = dot.tk_file;
                expr->ex_line = dot.tk_line;
        }
+
        expr->ex_type = tp;
        expr->ex_class = Oper;
        /* combine depths and flags of both expressions */
@@ -368,6 +369,9 @@ new_oper(tp, e1, oper, e2)
        op->op_oper = oper;
        op->op_left = e1;
        op->op_right = e2;
+#ifdef LINT
+       lint_new_oper(expr);
+#endif LINT
        return expr;
 }
 
index d344d1e..3865ab2 100644 (file)
@@ -9,7 +9,7 @@
        a union of various goodies, we define them first; so be patient.
 */
 
-#include "nofloat.h"
+#include       "nofloat.h"
 
 /* classes of value */
 #define Const  1
index 954d0cd..2e7b71d 100644 (file)
@@ -4,9 +4,23 @@
  */
 /* $Header$ */
 
+/*     To determine the minimum scope of a local variable, all (braced)
+       scopes are numbered consecutively.  Next we maintain an array which
+       maps the nesting depth (level) onto the scope number; we record
+       the scope number of the first application of a local variable
+       in its definition.  Each further application requires that the
+       level of the variable be at least large enough to comprise both
+       the present scope and that of its first application.  That level
+       number is determined by searching the array and is then recorded in
+       the definition (beacuse it is always equal to or smaller than the
+       level already there).
+
+       The array is implemented as a linked list of struct brace.
+*/
+
 struct brace   {
        struct brace *next;
-       int br_count;                   /* ??? */
+       int br_count;
        int br_level;
 };
 
index 1379ad2..45c2259 100644 (file)
@@ -166,7 +166,6 @@ lint_oper(expr, val, used)
        case ANDAB:
        case XORAB:
        case ORAB:
-               lint_conversion(oper, right->ex_type, left->ex_type);
                /* for cases like i += l; */
                esp1 = lint_expr(right, RVAL, USED);
                if (oper != '=') {
@@ -269,7 +268,6 @@ lint_oper(expr, val, used)
        case INT2FLOAT:
        case FLOAT2INT:
        case FLOAT2FLOAT:
-               lint_conversion(oper, right->ex_type, left->ex_type);
                return lint_expr(right, RVAL, USED);
 
        case '<':
index 84e68d7..beca5ca 100644 (file)
 extern char *symbol2str();
 extern struct type *func_type;
 
-lint_conversion(oper, from_type, to_type)
-       struct type *from_type, *to_type;
+lint_new_oper(expr)
+       struct expr *expr;
 {
-       register int from = from_type->tp_fund;
-       register int to = to_type->tp_fund;
+       /*      Does additional checking on a newly constructed expr node
+               of class Oper.
 
+               Some code in this routine could be contracted, but since
+               I am not sure we have covered the entire ground, we'll
+               leave the contracting for some rainy day.
+       */
+       register struct expr *left = expr->OP_LEFT;
+       register struct expr *right = expr->OP_RIGHT;
+       register int oper = expr->OP_OPER;
+       register int l_fund =
+               left == 0 ? 0 :                 /* for monadics */
+               left->ex_type->tp_fund;
+       register int r_fund =
+               right == 0 ? 0 :                /* for ( without parameters */
+               right->ex_type->tp_fund;
+
+       /*      In ch7.c, in ch7asgn(), a combined operator/assignment
+               is hammered into correctness by repeated application of
+               ch7bin(), which calls new_oper(), which calls lint_new_oper().
+               These spurious calls understandably cause spurious error
+               messages, which we don't like.  So we try to suppress these
+               wierd calls here.  This refers to the code marked
+                       this is really $#@&*%$# !
+               in ch7asgn().
+       */
        switch (oper) {
-       case RETURN:    /* not really an oper, but it works */
-       case INT2INT:
-       case '=':
        case PLUSAB:
        case MINAB:
        case TIMESAB:
@@ -47,19 +67,225 @@ lint_conversion(oper, from_type, to_type)
        case ANDAB:
        case XORAB:
        case ORAB:
-               if (    (from == LONG && to != LONG)
-               ||      (from == DOUBLE && to != DOUBLE)
+               /* is the left operand wierd? */
+               if (    left->ex_class == Value
+               &&      left->VL_CLASS == Const
+               &&      left->VL_VALUE == 0
                ) {
-                       awarning("conversion from %s to %s may lose accuracy",
-                               symbol2str(from), symbol2str(to));
+                       return;
                }
        }
+
+       switch (oper) {
+       case '=':
+               lint_conversion(right, l_fund);
+               break;
+
+       case PLUSAB:
+               lint_conversion(right, l_fund);
+       case '+':
+               lint_enum_arith(l_fund, oper, r_fund);
+               break;
+
+       case MINAB:
+               lint_conversion(right, l_fund);
+       case '-':
+               if (left == 0) {
+                       /* unary */
+                       if (r_fund == ENUM)
+                               warning("negating an enum");
+               }
+               else {
+                       /* binary */
+                       if (l_fund == ENUM && r_fund == ENUM) {
+                               if (left->ex_type != right->ex_type)
+                                       warning("subtracting enums of different type");
+                               /* update the type, cem does not do it */
+                               expr->ex_type = int_type;
+                       }
+                       lint_enum_arith(l_fund, oper, r_fund);
+               }
+               break;
+
+       case TIMESAB:
+               lint_conversion(right, l_fund);
+       case '*':
+               if (left == 0) {
+                       /* unary */
+               }
+               else {
+                       /* binary */
+                       if (l_fund == ENUM || r_fund == ENUM)
+                               warning("multiplying enum");
+               }
+               break;
+
+       case DIVAB:
+               lint_conversion(right, l_fund);
+       case '/':
+               if (l_fund == ENUM || r_fund == ENUM)
+                       warning("division on enum");
+               break;
+
+       case MODAB:
+               lint_conversion(right, l_fund);
+       case '%':
+               if (l_fund == ENUM || r_fund == ENUM)
+                       warning("modulo on enum");
+               break;
+
+       case '~':
+               if (r_fund == ENUM || r_fund == FLOAT || r_fund == DOUBLE)
+                       warning("~ on %s", symbol2str(r_fund));
+               break;
+
+       case '!':
+               if (r_fund == ENUM)
+                       warning("! on enum");
+               break;
+
+       case INT2INT:
+       case INT2FLOAT:
+       case FLOAT2INT:
+       case FLOAT2FLOAT:
+               lint_conversion(right, l_fund);
+               break;
+
+       case '<':
+       case '>':
+       case LESSEQ:
+       case GREATEREQ:
+       case EQUAL:
+       case NOTEQUAL:
+               if (    (l_fund == ENUM || r_fund == ENUM)
+               &&      left->ex_type != right->ex_type
+               ) {
+                       warning("comparing enum with non-enum");
+               }
+               lint_relop(left, right, oper);
+               lint_relop(right, left, 
+                       oper == '<' ? '>' :
+                       oper == '>' ? '<' :
+                       oper == LESSEQ ? GREATEREQ :
+                       oper == GREATEREQ ? LESSEQ :
+                       oper
+               );
+               break;
+
+       case LEFTAB:
+       case RIGHTAB:
+               lint_conversion(right, l_fund);
+       case LEFT:
+       case RIGHT:
+               if (l_fund == ENUM || r_fund == ENUM)
+                       warning("shift on enum");
+               break;
+
+       case ANDAB:
+       case ORAB:
+       case XORAB:
+               lint_conversion(right, l_fund);
+       case '&':
+       case '|':
+       case '^':
+               if (l_fund == ENUM || r_fund == ENUM)
+                       warning("bit operations on enum");
+               break;
+
+       case ',':
+       case '?':
+       case ':':
+       case AND:
+       case OR:
+       case POSTINCR:
+       case POSTDECR:
+       case PLUSPLUS:
+       case MINMIN:
+       case '(':
+       case '.':
+       case ARROW:
+       default:
+               /* OK with lint */
+               break;
+       }
 }
 
-lint_ret_conv(from_type)
-       struct type *from_type;
+lint_enum_arith(l_fund, oper, r_fund)
+       int l_fund, oper, r_fund;
 {
-       lint_conversion(RETURN, from_type, func_type);
+       if (    l_fund == ENUM
+       &&      r_fund != CHAR
+       &&      r_fund != SHORT
+       &&      r_fund != INT
+       ) {
+               warning("%s on enum and %s",
+                       symbol2str(oper), symbol2str(r_fund));
+       }
+       else
+       if (    r_fund == ENUM
+       &&      l_fund != CHAR
+       &&      l_fund != SHORT
+       &&      l_fund != INT
+       ) {
+               warning("%s on %s and enum",
+                       symbol2str(oper), symbol2str(r_fund));
+       }
+}
+
+lint_conversion(from_expr, to_fund)
+       struct expr *from_expr;
+       int to_fund;
+{
+       register int from_fund = from_expr->ex_type->tp_fund;
+
+       /*      was there an attempt to reduce the type of the from_expr
+               of the form
+                       expr & 0377
+               or something like this?
+       */
+       if (from_expr->ex_class == Oper && from_expr->OP_OPER == INT2INT) {
+               from_expr = from_expr->OP_LEFT;
+       }
+       if (from_expr->ex_class == Oper && from_expr->OP_OPER == '&') {
+               struct expr *bits =
+                       is_cp_cst(from_expr->OP_LEFT) ? from_expr->OP_LEFT :
+                       is_cp_cst(from_expr->OP_RIGHT) ? from_expr->OP_RIGHT :
+                       0;
+
+               if (bits) {
+                       arith val = bits->VL_VALUE;
+
+                       if (val < 256)
+                               from_fund = CHAR;
+                       else if (val < 256)
+                               from_fund = SHORT;
+               }
+       }
+       if (numsize(from_fund) > numsize(to_fund)) {
+               awarning("conversion from %s to %s may lose accuracy",
+                       symbol2str(from_fund), symbol2str(to_fund));
+       }
+}
+
+int
+numsize(fund)
+{
+       switch (fund) {
+       case CHAR:      return 1;
+       case SHORT:     return 2;
+       case INT:       return 3;
+       case ENUM:      return 3;
+       case LONG:      return 4;
+       case FLOAT:     return 5;
+       case DOUBLE:    return 6;
+       default:        return 0;
+       }
+}
+
+lint_ret_conv(from_expr)
+       struct expr *from_expr;
+{
+       lint_conversion(from_expr, func_type->tp_fund);
 }
 
 lint_ptr_conv(from, to)
@@ -117,6 +343,13 @@ lint_relop(left, right, oper)
        struct expr *left, *right;
        int oper;       /* '<', '>', LESSEQ, GREATEREQ, EQUAL, NOTEQUAL */
 {
+       /* left operand may be converted */
+       if (    left->ex_class == Oper
+       &&      left->OP_OPER == INT2INT
+       ) {
+               left = left->OP_RIGHT;
+       }
+
        /* <unsigned> <relop> <neg-const|0> is doubtful */
        if (    left->ex_type->tp_unsigned
        &&      right->ex_class == Value
index 39f510b..9d053e3 100644 (file)
@@ -964,7 +964,6 @@ lint_label()
 */
        register struct auto_def *a = top_ls->ls_current->st_auto_list;
 
-       hwarning("all auto variables assumed initialized at label");
        while (a) {
                a->ad_maybe_set = 0;
                a->ad_set = 1;
index 4fc91ef..53b0aeb 100644 (file)
@@ -417,7 +417,7 @@ return_statement
                expression(&expr)
                {
 #ifdef LINT
-                       lint_ret_conv(expr->ex_type);
+                       lint_ret_conv(expr);
 #endif LINT
 
                        do_return_expr(expr);