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 "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;
{

View 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);

View 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;

View 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:

View 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;
}

View 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

View 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;
};

View 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 '<':

View file

@ -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;
}
/* <unsigned> <relop> <neg-const|0> is doubtful */
if ( left->ex_type->tp_unsigned
&& right->ex_class == Value

View 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;

View 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);