lint: additional type tests in expressions
This commit is contained in:
parent
6ae90c8f34
commit
4f8b2e9926
|
@ -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;
|
||||||
{
|
{
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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 '<':
|
||||||
|
|
|
@ -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));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
lint_ret_conv(from_type)
|
switch (oper) {
|
||||||
struct type *from_type;
|
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_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)
|
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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue