lint: additional type tests in expressions

This commit is contained in:
dick 1988-09-29 15:24:02 +00:00
parent 6ae90c8f34
commit 4f8b2e9926
11 changed files with 320 additions and 77 deletions

View file

@ -12,6 +12,7 @@
*/ */
#include <alloc.h> #include <alloc.h>
#include "lint.h"
#include "nofloat.h" #include "nofloat.h"
#include "nobitfield.h" #include "nobitfield.h"
#include "idf.h" #include "idf.h"
@ -163,7 +164,9 @@ any2arith(expp, oper)
else else
expr_warning(*expp, "%s on enum", symbol2str(oper)); expr_warning(*expp, "%s on enum", symbol2str(oper));
#endif NOROPTION #endif NOROPTION
#ifndef LINT
int2int(expp, int_type); int2int(expp, int_type);
#endif LINT
break; break;
#ifndef NOFLOAT #ifndef NOFLOAT
case FLOAT: case FLOAT:
@ -420,53 +423,6 @@ is_test_op(oper)
/*NOTREACHED*/ /*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) any2opnd(expp, oper)
register struct expr **expp; register struct expr **expp;
{ {

View file

@ -163,21 +163,26 @@ ch7cast(expp, oper, tp)
if ((*expp)->ex_class == String) if ((*expp)->ex_class == String)
string2pointer(*expp); string2pointer(*expp);
oldtp = (*expp)->ex_type; oldtp = (*expp)->ex_type;
#ifndef NOBITFIELD #ifndef NOBITFIELD
if (oldtp->tp_fund == FIELD) { if (oldtp->tp_fund == FIELD) {
field2arith(expp); field2arith(expp);
ch7cast(expp, oper, tp); ch7cast(expp, oper, tp);
} }
else else
if (tp->tp_fund == FIELD) if (tp->tp_fund == FIELD) {
ch7cast(expp, oper, tp->tp_up); ch7cast(expp, oper, tp->tp_up);
}
else else
#endif NOBITFIELD #endif NOBITFIELD
if (oldtp == tp) if (oldtp == tp) {
{} /* life is easy */ /* life is easy */
}
else else
if (tp->tp_fund == VOID) /* Easy again */ if (tp->tp_fund == VOID) {
/* Easy again */
(*expp)->ex_type = void_type; (*expp)->ex_type = void_type;
}
else else
if (is_arith_type(oldtp) && is_arith_type(tp)) { if (is_arith_type(oldtp) && is_arith_type(tp)) {
int oldi = is_integral_type(oldtp); int oldi = is_integral_type(oldtp);
@ -191,7 +196,14 @@ ch7cast(expp, oper, tp)
expr_warning(*expp, expr_warning(*expp,
"%s on enums of different types", "%s on enums of different types",
symbol2str(oper)); symbol2str(oper));
#ifdef LINT
if (oper == CAST)
(*expp)->ex_type = tp;
else
int2int(expp, tp); int2int(expp, tp);
#else LINT
int2int(expp, tp);
#endif LINT
} }
#ifndef NOFLOAT #ifndef NOFLOAT
else else
@ -200,13 +212,37 @@ ch7cast(expp, oper, tp)
expr_warning(*expp, expr_warning(*expp,
"conversion of enum to %s\n", "conversion of enum to %s\n",
symbol2str(tp->tp_fund)); symbol2str(tp->tp_fund));
#ifdef LINT
if (oper == CAST)
(*expp)->ex_type = tp;
else
int2float(expp, tp); int2float(expp, tp);
#else LINT
int2float(expp, tp);
#endif LINT
} }
else else
if (!oldi && i) if (!oldi && i) {
#ifdef LINT
if (oper == CAST)
(*expp)->ex_type = tp;
else
float2int(expp, tp); float2int(expp, tp);
else /* !oldi && !i */ #else LINT
float2int(expp, tp);
#endif LINT
}
else {
/* !oldi && !i */
#ifdef LINT
if (oper == CAST)
(*expp)->ex_type = tp;
else
float2float(expp, tp); float2float(expp, tp);
#else LINT
float2float(expp, tp);
#endif LINT
}
#else NOFLOAT #else NOFLOAT
else { else {
crash("(ch7cast) floats not implemented\n"); crash("(ch7cast) floats not implemented\n");
@ -269,8 +305,10 @@ ch7cast(expp, oper, tp)
(*expp)->ex_type = tp; (*expp)->ex_type = tp;
} }
else 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 */ (*expp)->ex_type = tp; /* brute force */
}
else else
if (oldtp->tp_size == tp->tp_size && oper == CAST) { if (oldtp->tp_size == tp->tp_size && oper == CAST) {
expr_warning(*expp, "dubious conversion based on equal size"); expr_warning(*expp, "dubious conversion based on equal size");
@ -321,6 +359,7 @@ ch7asgn(expp, oper, expr)
struct expr *extmp = intexpr((arith)0, INT); struct expr *extmp = intexpr((arith)0, INT);
/* this is really $#@&*%$# ! */ /* this is really $#@&*%$# ! */
/* if you correct this, please correct lint_new_oper() too */
extmp->ex_lvalue = 1; extmp->ex_lvalue = 1;
extmp->ex_type = exp->ex_type; extmp->ex_type = exp->ex_type;
ch7bin(&extmp, oper, expr); ch7bin(&extmp, oper, expr);

View file

@ -303,7 +303,7 @@ mk_binop(expp, oper, expr, commutative)
register struct expr *expr; register struct expr *expr;
{ {
/* Constructs in *expp the operation indicated by the operands. /* Constructs in *expp the operation indicated by the operands.
"commutative" indicates wether "oper" is a commutative "commutative" indicates whether "oper" is a commutative
operator. operator.
*/ */
register struct expr *ex = *expp; register struct expr *ex = *expp;

View file

@ -254,8 +254,8 @@ type2str(tp)
sprint(buf, "<NILTYPE>"); sprint(buf, "<NILTYPE>");
return 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) { while (ops) {
switch (tp->tp_fund) { switch (tp->tp_fund) {
case POINTER: case POINTER:

View file

@ -352,6 +352,7 @@ new_oper(tp, e1, oper, e2)
expr->ex_file = dot.tk_file; expr->ex_file = dot.tk_file;
expr->ex_line = dot.tk_line; expr->ex_line = dot.tk_line;
} }
expr->ex_type = tp; expr->ex_type = tp;
expr->ex_class = Oper; expr->ex_class = Oper;
/* combine depths and flags of both expressions */ /* combine depths and flags of both expressions */
@ -368,6 +369,9 @@ new_oper(tp, e1, oper, e2)
op->op_oper = oper; op->op_oper = oper;
op->op_left = e1; op->op_left = e1;
op->op_right = e2; op->op_right = e2;
#ifdef LINT
lint_new_oper(expr);
#endif LINT
return expr; return expr;
} }

View file

@ -4,9 +4,23 @@
*/ */
/* $Header$ */ /* $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 {
struct brace *next; struct brace *next;
int br_count; /* ??? */ int br_count;
int br_level; int br_level;
}; };

View file

@ -166,7 +166,6 @@ lint_oper(expr, val, used)
case ANDAB: case ANDAB:
case XORAB: case XORAB:
case ORAB: case ORAB:
lint_conversion(oper, right->ex_type, left->ex_type);
/* for cases like i += l; */ /* for cases like i += l; */
esp1 = lint_expr(right, RVAL, USED); esp1 = lint_expr(right, RVAL, USED);
if (oper != '=') { if (oper != '=') {
@ -269,7 +268,6 @@ lint_oper(expr, val, used)
case INT2FLOAT: case INT2FLOAT:
case FLOAT2INT: case FLOAT2INT:
case FLOAT2FLOAT: case FLOAT2FLOAT:
lint_conversion(oper, right->ex_type, left->ex_type);
return lint_expr(right, RVAL, USED); return lint_expr(right, RVAL, USED);
case '<': case '<':

View file

@ -27,16 +27,36 @@
extern char *symbol2str(); extern char *symbol2str();
extern struct type *func_type; extern struct type *func_type;
lint_conversion(oper, from_type, to_type) lint_new_oper(expr)
struct type *from_type, *to_type; struct expr *expr;
{ {
register int from = from_type->tp_fund; /* Does additional checking on a newly constructed expr node
register int to = to_type->tp_fund; 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) { switch (oper) {
case RETURN: /* not really an oper, but it works */
case INT2INT:
case '=':
case PLUSAB: case PLUSAB:
case MINAB: case MINAB:
case TIMESAB: case TIMESAB:
@ -47,19 +67,225 @@ lint_conversion(oper, from_type, to_type)
case ANDAB: case ANDAB:
case XORAB: case XORAB:
case ORAB: case ORAB:
if ( (from == LONG && to != LONG) /* is the left operand wierd? */
|| (from == DOUBLE && to != DOUBLE) if ( left->ex_class == Value
&& left->VL_CLASS == Const
&& left->VL_VALUE == 0
) { ) {
awarning("conversion from %s to %s may lose accuracy", return;
symbol2str(from), symbol2str(to));
} }
} }
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) lint_enum_arith(l_fund, oper, r_fund)
struct type *from_type; 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) lint_ptr_conv(from, to)
@ -117,6 +343,13 @@ lint_relop(left, right, oper)
struct expr *left, *right; struct expr *left, *right;
int oper; /* '<', '>', LESSEQ, GREATEREQ, EQUAL, NOTEQUAL */ 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 */ /* <unsigned> <relop> <neg-const|0> is doubtful */
if ( left->ex_type->tp_unsigned if ( left->ex_type->tp_unsigned
&& right->ex_class == Value && right->ex_class == Value

View file

@ -964,7 +964,6 @@ lint_label()
*/ */
register struct auto_def *a = top_ls->ls_current->st_auto_list; register struct auto_def *a = top_ls->ls_current->st_auto_list;
hwarning("all auto variables assumed initialized at label");
while (a) { while (a) {
a->ad_maybe_set = 0; a->ad_maybe_set = 0;
a->ad_set = 1; a->ad_set = 1;

View file

@ -417,7 +417,7 @@ return_statement
expression(&expr) expression(&expr)
{ {
#ifdef LINT #ifdef LINT
lint_ret_conv(expr->ex_type); lint_ret_conv(expr);
#endif LINT #endif LINT
do_return_expr(expr); do_return_expr(expr);