From 4f8b2e9926e46643d10bb4428e500a3498713bb2 Mon Sep 17 00:00:00 2001 From: dick Date: Thu, 29 Sep 1988 15:24:02 +0000 Subject: [PATCH] lint: additional type tests in expressions --- lang/cem/cemcom/arith.c | 50 +------ lang/cem/cemcom/ch7.c | 53 +++++++- lang/cem/cemcom/ch7bin.c | 2 +- lang/cem/cemcom/dumpidf.c | 4 +- lang/cem/cemcom/expr.c | 4 + lang/cem/cemcom/expr.str | 2 +- lang/cem/cemcom/l_brace.str | 16 ++- lang/cem/cemcom/l_lint.c | 2 - lang/cem/cemcom/l_misc.c | 261 ++++++++++++++++++++++++++++++++++-- lang/cem/cemcom/l_states.c | 1 - lang/cem/cemcom/statement.g | 2 +- 11 files changed, 320 insertions(+), 77 deletions(-) diff --git a/lang/cem/cemcom/arith.c b/lang/cem/cemcom/arith.c index b8928a1bf..04f9da612 100644 --- a/lang/cem/cemcom/arith.c +++ b/lang/cem/cemcom/arith.c @@ -12,6 +12,7 @@ */ #include +#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; { diff --git a/lang/cem/cemcom/ch7.c b/lang/cem/cemcom/ch7.c index 597debca4..bb213c462 100644 --- a/lang/cem/cemcom/ch7.c +++ b/lang/cem/cemcom/ch7.c @@ -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); diff --git a/lang/cem/cemcom/ch7bin.c b/lang/cem/cemcom/ch7bin.c index a24bee9ac..c26a89ebd 100644 --- a/lang/cem/cemcom/ch7bin.c +++ b/lang/cem/cemcom/ch7bin.c @@ -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; diff --git a/lang/cem/cemcom/dumpidf.c b/lang/cem/cemcom/dumpidf.c index b07ebc93b..cf92c1d9b 100644 --- a/lang/cem/cemcom/dumpidf.c +++ b/lang/cem/cemcom/dumpidf.c @@ -254,8 +254,8 @@ type2str(tp) sprint(buf, ""); 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: diff --git a/lang/cem/cemcom/expr.c b/lang/cem/cemcom/expr.c index 21b8815cd..0b317b4ab 100644 --- a/lang/cem/cemcom/expr.c +++ b/lang/cem/cemcom/expr.c @@ -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; } diff --git a/lang/cem/cemcom/expr.str b/lang/cem/cemcom/expr.str index d344d1e30..3865ab28f 100644 --- a/lang/cem/cemcom/expr.str +++ b/lang/cem/cemcom/expr.str @@ -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 diff --git a/lang/cem/cemcom/l_brace.str b/lang/cem/cemcom/l_brace.str index 954d0cdef..2e7b71da3 100644 --- a/lang/cem/cemcom/l_brace.str +++ b/lang/cem/cemcom/l_brace.str @@ -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; }; diff --git a/lang/cem/cemcom/l_lint.c b/lang/cem/cemcom/l_lint.c index 1379ad2ae..45c2259de 100644 --- a/lang/cem/cemcom/l_lint.c +++ b/lang/cem/cemcom/l_lint.c @@ -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 '<': diff --git a/lang/cem/cemcom/l_misc.c b/lang/cem/cemcom/l_misc.c index 84e68d764..beca5ca91 100644 --- a/lang/cem/cemcom/l_misc.c +++ b/lang/cem/cemcom/l_misc.c @@ -27,16 +27,36 @@ 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; + } + /* is doubtful */ if ( left->ex_type->tp_unsigned && right->ex_class == Value diff --git a/lang/cem/cemcom/l_states.c b/lang/cem/cemcom/l_states.c index 39f510ba9..9d053e3ad 100644 --- a/lang/cem/cemcom/l_states.c +++ b/lang/cem/cemcom/l_states.c @@ -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; diff --git a/lang/cem/cemcom/statement.g b/lang/cem/cemcom/statement.g index 4fc91efb3..53b0aeba2 100644 --- a/lang/cem/cemcom/statement.g +++ b/lang/cem/cemcom/statement.g @@ -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); -- 2.34.1