better evaluation order checking in expressions

This commit is contained in:
dick 1989-02-02 13:57:07 +00:00
parent f7df668450
commit f70dfe4d00
16 changed files with 367 additions and 227 deletions

View file

@ -126,7 +126,7 @@ LINT = /usr/bin/lint
LINTFLAGS = LINTFLAGS =
MYLINT = ../lpass2/lint MYLINT = ../lpass2/lint
MYLINTFLAGS = #-xh MYLINTFLAGS = -xh
#EXCLEXCLEXCLEXCL #EXCLEXCLEXCLEXCL
@ -800,6 +800,7 @@ l_lint.o: def.h
l_lint.o: expr.h l_lint.o: expr.h
l_lint.o: file_info.h l_lint.o: file_info.h
l_lint.o: idf.h l_lint.o: idf.h
l_lint.o: interface.h
l_lint.o: l_lint.h l_lint.o: l_lint.h
l_lint.o: l_outdef.h l_lint.o: l_outdef.h
l_lint.o: l_state.h l_lint.o: l_state.h
@ -822,6 +823,7 @@ l_states.o: def.h
l_states.o: expr.h l_states.o: expr.h
l_states.o: file_info.h l_states.o: file_info.h
l_states.o: idf.h l_states.o: idf.h
l_states.o: interface.h
l_states.o: l_brace.h l_states.o: l_brace.h
l_states.o: l_comment.h l_states.o: l_comment.h
l_states.o: l_lint.h l_states.o: l_lint.h
@ -844,6 +846,7 @@ l_misc.o: def.h
l_misc.o: expr.h l_misc.o: expr.h
l_misc.o: file_info.h l_misc.o: file_info.h
l_misc.o: idf.h l_misc.o: idf.h
l_misc.o: interface.h
l_misc.o: l_state.h l_misc.o: l_state.h
l_misc.o: label.h l_misc.o: label.h
l_misc.o: level.h l_misc.o: level.h
@ -864,6 +867,7 @@ l_ev_ord.o: def.h
l_ev_ord.o: expr.h l_ev_ord.o: expr.h
l_ev_ord.o: file_info.h l_ev_ord.o: file_info.h
l_ev_ord.o: idf.h l_ev_ord.o: idf.h
l_ev_ord.o: interface.h
l_ev_ord.o: l_lint.h l_ev_ord.o: l_lint.h
l_ev_ord.o: l_state.h l_ev_ord.o: l_state.h
l_ev_ord.o: label.h l_ev_ord.o: label.h
@ -879,12 +883,14 @@ l_outdef.o: LLlex.h
l_outdef.o: Lpars.h l_outdef.o: Lpars.h
l_outdef.o: arith.h l_outdef.o: arith.h
l_outdef.o: assert.h l_outdef.o: assert.h
l_outdef.o: code.h
l_outdef.o: debug.h l_outdef.o: debug.h
l_outdef.o: def.h l_outdef.o: def.h
l_outdef.o: expr.h l_outdef.o: expr.h
l_outdef.o: field.h l_outdef.o: field.h
l_outdef.o: file_info.h l_outdef.o: file_info.h
l_outdef.o: idf.h l_outdef.o: idf.h
l_outdef.o: interface.h
l_outdef.o: l_class.h l_outdef.o: l_class.h
l_outdef.o: l_comment.h l_outdef.o: l_comment.h
l_outdef.o: l_lint.h l_outdef.o: l_lint.h
@ -900,6 +906,8 @@ l_outdef.o: stack.h
l_outdef.o: struct.h l_outdef.o: struct.h
l_outdef.o: type.h l_outdef.o: type.h
l_comment.o: arith.h l_comment.o: arith.h
l_comment.o: interface.h
l_comment.o: l_comment.h
l_comment.o: l_state.h l_comment.o: l_state.h
l_comment.o: lint.h l_comment.o: lint.h
l_comment.o: spec_arith.h l_comment.o: spec_arith.h
@ -991,7 +999,6 @@ ival.o: LLlex.h
ival.o: Lpars.h ival.o: Lpars.h
ival.o: arith.h ival.o: arith.h
ival.o: assert.h ival.o: assert.h
ival.o: code.h
ival.o: debug.h ival.o: debug.h
ival.o: def.h ival.o: def.h
ival.o: estack.h ival.o: estack.h

View file

@ -258,7 +258,7 @@ ch7cast(expp, oper, tp)
expr_warning(*expp, "incompatible pointers in %s", expr_warning(*expp, "incompatible pointers in %s",
symbol2str(oper)); symbol2str(oper));
#ifdef LINT #ifdef LINT
if (oper == CAST) if (oper != CAST)
lint_ptr_conv(oldtp->tp_up->tp_fund, tp->tp_up->tp_fund); lint_ptr_conv(oldtp->tp_up->tp_fund, tp->tp_up->tp_fund);
#endif LINT #endif LINT
(*expp)->ex_type = tp; /* free conversion */ (*expp)->ex_type = tp; /* free conversion */

View file

@ -71,9 +71,7 @@ ch7mon(oper, expp)
expr_error(*expp, "& applied to non-lvalue"); expr_error(*expp, "& applied to non-lvalue");
else { else {
/* assume that enums are already filtered out */ /* assume that enums are already filtered out */
if ( (*expp)->ex_class == Value if (ISNAME(*expp)) {
&& (*expp)->VL_CLASS == Name
) {
register struct def *def = register struct def *def =
(*expp)->VL_IDF->id_def; (*expp)->VL_IDF->id_def;
@ -147,10 +145,7 @@ ch7mon(oper, expp)
ch7incr(expp, oper); ch7incr(expp, oper);
break; break;
case SIZEOF: case SIZEOF:
if ( (*expp)->ex_class == Value if (ISNAME(*expp) && (*expp)->VL_IDF->id_def->df_formal_array)
&& (*expp)->VL_CLASS == Name
&& (*expp)->VL_IDF->id_def->df_formal_array
)
warning("sizeof formal array %s is sizeof pointer!", warning("sizeof formal array %s is sizeof pointer!",
(*expp)->VL_IDF->id_text); (*expp)->VL_IDF->id_text);
expr = intexpr((*expp)->ex_type == string_type ? expr = intexpr((*expp)->ex_type == string_type ?

View file

@ -559,7 +559,7 @@ code_expr(expr, val, code, tlbl, flbl)
C_lin((arith)(expr->ex_line)); C_lin((arith)(expr->ex_line));
EVAL(expr, val, code, tlbl, flbl); EVAL(expr, val, code, tlbl, flbl);
#else LINT #else LINT
pre_lint_expr(expr, RVAL, code ? USED : IGNORED); lint_expr(expr, code ? USED : IGNORED);
#endif LINT #endif LINT
} }

View file

@ -453,7 +453,7 @@ EVAL(expr, val, code, true_label, false_label)
arith ParSize = (arith)0; arith ParSize = (arith)0;
label setjmp_label = 0; label setjmp_label = 0;
if (left->ex_class == Value && left->VL_CLASS == Name) { if (ISNAME(left)) {
if (left->VL_IDF->id_special == SP_SETJMP) { if (left->VL_IDF->id_special == SP_SETJMP) {
label addr_label = data_label(); label addr_label = data_label();
@ -480,7 +480,7 @@ EVAL(expr, val, code, true_label, false_label)
NO_LABEL, NO_LABEL); NO_LABEL, NO_LABEL);
ParSize += ATW(ex->ex_type->tp_size); ParSize += ATW(ex->ex_type->tp_size);
} }
if (left->ex_class == Value && left->VL_CLASS == Name) { if (ISNAME(left)) {
/* e.g., main() { (*((int (*)())0))(); } */ /* e.g., main() { (*((int (*)())0))(); } */
C_cal(left->VL_IDF->id_text); C_cal(left->VL_IDF->id_text);
if (setjmp_label) { if (setjmp_label) {
@ -913,7 +913,7 @@ load_val(expr, rlval)
register struct idf *id = expr->VL_IDF; register struct idf *id = expr->VL_IDF;
register struct def *df = id->id_def; register struct def *df = id->id_def;
ASSERT(expr->VL_CLASS == Name); ASSERT(ISNAME(expr));
if (df->df_type->tp_fund == FUNCTION) { if (df->df_type->tp_fund == FUNCTION) {
/* the previous statement tried to catch a function /* the previous statement tried to catch a function
identifier, which may be cast to a pointer to a identifier, which may be cast to a pointer to a

View file

@ -104,8 +104,11 @@ struct expr {
#define NILEXPR ((struct expr *)0) #define NILEXPR ((struct expr *)0)
/* some useful tests */
#define ISNAME(e) ((e)->ex_class == Value && (e)->VL_CLASS == Name)
#define ISCOMMA(e) ((e)->ex_class == Oper && (e)->OP_OPER == INITCOMMA)
extern struct expr *intexpr(), *new_oper(); extern struct expr *intexpr(), *new_oper();
/* ALLOCDEF "expr" 20 */ /* ALLOCDEF "expr" 20 */
#define ISCOMMA(e) ((e)->ex_class == Oper && (e)->OP_OPER == INITCOMMA)

View file

@ -3,6 +3,6 @@
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright". * See the copyright notice in the ACK home directory, in the file "Copyright".
*/ */
#define PRIVATE #define PRIVATE /*static /* or not */
#define IMPORT extern #define IMPORT extern
#define EXPORT #define EXPORT

View file

@ -27,7 +27,6 @@
#include "LLlex.h" #include "LLlex.h"
#include "noRoption.h" #include "noRoption.h"
#include "estack.h" #include "estack.h"
#include "code.h"
#ifdef LINT #ifdef LINT
#include "l_lint.h" #include "l_lint.h"
#endif LINT #endif LINT
@ -54,7 +53,7 @@ initial_value(register struct type **tpp; register struct expr **expp;) :
assignment_expression(expp) assignment_expression(expp)
{ {
#ifdef LINT #ifdef LINT
pre_lint_expr(*expp, RVAL, USED); lint_expr(*expp, USED);
#endif LINT #endif LINT
if ((*expp)->ex_type->tp_fund == ARRAY) if ((*expp)->ex_type->tp_fund == ARRAY)
array2pointer(*expp); array2pointer(*expp);

View file

@ -12,6 +12,7 @@
#ifdef LINT #ifdef LINT
#include <alloc.h> #include <alloc.h>
#include "interface.h"
#include "arith.h" #include "arith.h"
#include "l_state.h" #include "l_state.h"
#include "l_comment.h" #include "l_comment.h"
@ -24,13 +25,15 @@ extern char loptions[];
one token later. one token later.
*/ */
static int notreached; PRIVATE int notreached;
static int varargsN = -1; PRIVATE int varargsN = -1;
static int argsused; PRIVATE int argsused;
static int formatN; PRIVATE int formatN;
static int formatVAR; PRIVATE int formatVAR;
static char *format; PRIVATE char *format;
static char *prev_format; PRIVATE char *prev_format;
PRIVATE make_format();
int LINTLIB; /* file is lint library */ int LINTLIB; /* file is lint library */
int s_NOTREACHED; /* statement not reached */ int s_NOTREACHED; /* statement not reached */
@ -71,8 +74,8 @@ lint_comment_function()
formatVAR = 0; formatVAR = 0;
} }
static char buf[1000]; PRIVATE char buf[1000];
static char *bufpos; /* next free position in buf */ PRIVATE char *bufpos; /* next free position in buf */
lint_start_comment() lint_start_comment()
{ {
@ -139,6 +142,7 @@ lint_end_comment()
#define LETGIT 1 #define LETGIT 1
#define LETGITSPACE 2 #define LETGITSPACE 2
PRIVATE
make_format(argn, oldf) make_format(argn, oldf)
int argn; int argn;
char *oldf; char *oldf;

View file

@ -10,6 +10,7 @@
#ifdef LINT #ifdef LINT
#include <alloc.h> /* for st_free */ #include <alloc.h> /* for st_free */
#include "interface.h"
#include "assert.h" #include "assert.h"
#include "arith.h" /* definition arith */ #include "arith.h" /* definition arith */
#include "label.h" /* definition label */ #include "label.h" /* definition label */
@ -28,42 +29,56 @@
extern char *symbol2str(); extern char *symbol2str();
check_and_merge(espp, esp, com_oper) PRIVATE check_ev_order();
check_and_merge(expr, espp, esp)
struct expr *expr;
struct expr_state **espp, *esp; struct expr_state **espp, *esp;
{ {
/* Checks for undefined evaluation orders in case of a commutative operator. /* Checks for undefined evaluation orders in case of a non-sequencing operator.
* In addition the sets of used and set variables of both expressions are * In addition the sets of used and set variables of both expressions are
* united. * united.
* *espp will be pointing to this new list. esp is used for this list. * *espp will be pointing to this new list. esp is used for this list.
*/ */
register struct expr_state **pp, *p1, *p2; register struct expr_state **pp, *p1, *p2;
int oper = expr->OP_OPER;
int is_sequencer =
(oper == '?' || oper == OR || oper == AND || oper ==',');
for (p1 = *espp; p1; p1 = p1->next) { for (p1 = *espp; p1; p1 = p1->next) {
/* scan the list esp for the same variable */
p2 = esp; p2 = esp;
pp = &esp; pp = &esp;
while (p2) { while (p2) {
if ( /* p1 and p2 are the same */ if ( /* p1 and p2 refer to the same location */
p1->es_idf == p2->es_idf p1->es_idf == p2->es_idf
&& p1->es_offset == p2->es_offset && p1->es_offset == p2->es_offset
) { ) {
if (com_oper) /* check */
check_ev_order(p1, p2, com_oper); if (!is_sequencer)
check_ev_order(p1, p2, expr);
/* merge the info */
p1->es_used |= p2->es_used; p1->es_used |= p2->es_used;
p1->es_referred |= p2->es_referred;
p1->es_set |= p2->es_set; p1->es_set |= p2->es_set;
/* and remove the entry from esp */
*pp = p2->next; *pp = p2->next;
free_expr_state(p2); free_expr_state(p2);
p2 = *pp; p2 = *pp;
} }
else { else {
/* skip over the entry in esp */
pp = &p2->next; pp = &p2->next;
p2 = p2->next; p2 = p2->next;
} }
} }
} }
/* The rest of the list esp is pointing to, is put in front of the list /* If there is anything left in the list esp, this is put in
* *espp is now pointing to. front of the list *espp is now pointing to, and *espp will be
* *espp will be pointing to this new list. left pointing to this new list.
*/ */
if (!esp) if (!esp)
return; return;
p1 = *espp; p1 = *espp;
@ -73,44 +88,20 @@ check_and_merge(espp, esp, com_oper)
esp->next = p1; esp->next = p1;
} }
check_ev_order(esp1, esp2, com_oper) PRIVATE
check_ev_order(esp1, esp2, expr)
struct expr_state *esp1, *esp2; struct expr_state *esp1, *esp2;
struct expr *expr;
{ {
if ( (esp1->es_used && esp2->es_set) if ( (esp1->es_used && esp2->es_set)
|| (esp1->es_set && esp2->es_used) || (esp1->es_set && esp2->es_used)
|| (esp1->es_set && esp2->es_set) || (esp1->es_set && esp2->es_set)
) { ) {
warning("result of %s depends on evaluation order on %s", expr_warning(expr,
symbol2str(com_oper), "result of %s depends on evaluation order on %s",
symbol2str(expr->OP_OPER),
esp1->es_idf->id_text); esp1->es_idf->id_text);
} }
} }
add_expr_state(value, to_state, espp)
struct value value;
struct expr_state **espp;
{
register struct expr_state *esp = *espp;
ASSERT(value.vl_class == Name);
while ( esp
&& !( esp->es_idf == value.vl_data.vl_idf
&& esp->es_offset == value.vl_value
)
) {
esp = esp->next;
}
if (!esp) { /* create new expr_state */
esp = new_expr_state();
esp->es_idf = value.vl_data.vl_idf;
esp->es_offset = value.vl_value;
esp->next = *espp;
*espp = esp;
}
if (to_state == SET)
esp->es_set = 1;
else /* USED */
esp->es_used = 1;
}
#endif LINT #endif LINT

View file

@ -10,6 +10,8 @@
#ifdef LINT #ifdef LINT
#include <alloc.h> /* for st_free */ #include <alloc.h> /* for st_free */
#include "debug.h"
#include "interface.h"
#include "assert.h" #include "assert.h"
#include "arith.h" /* definition arith */ #include "arith.h" /* definition arith */
#include "label.h" /* definition label */ #include "label.h" /* definition label */
@ -30,9 +32,13 @@
extern char options[128]; extern char options[128];
extern char *symbol2str(); extern char *symbol2str();
static struct expr_state *lint_expr(); PRIVATE struct expr_state *expr2state();
static struct expr_state *lint_value(); PRIVATE struct expr_state *value2state();
static struct expr_state *lint_oper(); PRIVATE struct expr_state *oper2state();
PRIVATE expr_ignored();
PRIVATE add_expr_state();
PRIVATE referred_esp();
PRIVATE free_expr_states();
lint_init() lint_init()
{ {
@ -40,36 +46,22 @@ lint_init()
lint_init_stack(); lint_init_stack();
} }
pre_lint_expr(expr, val, used) lint_expr(expr, used)
struct expr *expr; struct expr *expr;
int val; /* LVAL or RVAL */ int used; /* USED or IGNORED */
int used;
{ {
/* Introduced to dispose the returned expression states */
register struct expr_state *esp; register struct expr_state *esp;
esp = lint_expr(expr, val, used); esp = expr2state(expr, RVAL, used);
referred_esp(esp);
free_expr_states(esp); free_expr_states(esp);
} }
free_expr_states(esp) PRIVATE struct expr_state *
register struct expr_state *esp; expr2state(expr, val, used)
{
register struct expr_state *esp2;
while (esp) {
esp2 = esp;
esp = esp->next;
free_expr_state(esp2);
}
}
static struct expr_state *
lint_expr(expr, val, used)
register struct expr *expr; register struct expr *expr;
int val; int val; /* RVAL or LVAL */
int used; int used; /* USED or IGNORED */
{ {
/* Main function to process an expression tree. /* Main function to process an expression tree.
* It returns a structure containing information about which variables * It returns a structure containing information about which variables
@ -85,19 +77,20 @@ lint_expr(expr, val, used)
switch (expr->ex_class) { switch (expr->ex_class) {
case Value: case Value:
return lint_value(expr, val); return value2state(expr, val);
case Oper: case Oper:
return lint_oper(expr, val, used); return oper2state(expr, val, used);
default: /* String Float Type */ default: /* String, Float, Type */
return 0; return 0;
} }
} }
static struct expr_state * PRIVATE struct expr_state *
lint_value(expr, val) value2state(expr, val)
register struct expr *expr; struct expr *expr;
int val; /* RVAL or LVAL */
{ {
switch (expr->VL_CLASS) { switch (expr->VL_CLASS) {
case Const: case Const:
@ -107,28 +100,21 @@ lint_value(expr, val)
case Name: case Name:
{ {
register struct idf *idf = expr->VL_IDF; register struct idf *idf = expr->VL_IDF;
struct expr_state *esp1 = 0; struct expr_state *esp = 0;
if (!idf || !idf->id_def) if (!idf || !idf->id_def)
return 0; return 0;
if ( val == LVAL if (val == RVAL && expr->ex_lvalue == 1) {
|| ( val == RVAL /* value of identifier used */
&& expr->ex_type->tp_fund == POINTER
&& !expr->ex_lvalue
)
) {
change_state(idf, SET);
idf->id_def->df_file =
Salloc(dot.tk_file,
strlen(dot.tk_file) + 1);
idf->id_def->df_line = dot.tk_line;
}
if (val == RVAL) {
change_state(idf, USED); change_state(idf, USED);
add_expr_state(expr->EX_VALUE, USED, &esp1); add_expr_state(expr->EX_VALUE, USED, &esp);
} }
return esp1; if (val == RVAL && expr->ex_lvalue == 0) {
/* address of identifier used */
add_expr_state(expr->EX_VALUE, REFERRED, &esp);
}
return esp;
} }
default: default:
@ -137,19 +123,31 @@ lint_value(expr, val)
} }
} }
static struct expr_state * /* Let's get this straight.
lint_oper(expr, val, used) An assignment is performed by elaborating the LHS and the RHS
collaterally, to use the A68 terminology, and then serially do the
actual assignment. This means:
1. evaluate the LHS as an LVAL,
2. evaluate the RHS as an RVAL,
3. merge them checking for interference,
4. set the result of the LHS to SET, if it is a named variable
*/
PRIVATE struct expr_state *
oper2state(expr, val, used)
struct expr *expr; struct expr *expr;
int val; int val; /* RVAL or LVAL */
int used; int used; /* USED or IGNORED */
{ {
register int oper = expr->OP_OPER; register int oper = expr->OP_OPER;
register struct expr *left = expr->OP_LEFT; register struct expr *left = expr->OP_LEFT;
register struct expr *right = expr->OP_RIGHT; register struct expr *right = expr->OP_RIGHT;
struct expr_state *esp1 = 0; struct expr_state *esp_l = 0;
struct expr_state *esp2 = 0; struct expr_state *esp_r = 0;
switch (oper) { switch (oper) {
/* assignments */
case '=': case '=':
case PLUSAB: case PLUSAB:
case MINAB: case MINAB:
@ -161,53 +159,42 @@ lint_oper(expr, val, used)
case ANDAB: case ANDAB:
case XORAB: case XORAB:
case ORAB: case ORAB:
/* for cases like i += l; */ /* evaluate the LHS, only once; see RM 7.14 */
esp1 = lint_expr(right, RVAL, USED); esp_l = expr2state(left, (oper == '=' ? LVAL : RVAL), USED);
if (oper != '=') {
/* i += 1; is interpreted as i = i + 1; */ /* evaluate the RHS as an RVAL and merge */
esp2 = lint_expr(left, RVAL, USED); esp_r = expr2state(right, RVAL, USED);
check_and_merge(&esp1, esp2, oper); check_and_merge(expr, &esp_l, esp_r);
/* set resulting variable, if any */
if (ISNAME(left)) {
change_state(left->VL_IDF, SET);
add_expr_state(left->EX_VALUE, SET, &esp_l);
} }
esp2 = lint_expr(left, LVAL, USED);
/* for cases like i = i + 1; and i not set, this return esp_l;
** order is essential
*/
check_and_merge(&esp1, esp2, oper);
if ( left->ex_class == Value
&& left->VL_CLASS == Name
) {
add_expr_state(left->EX_VALUE, SET, &esp1);
}
return esp1;
case POSTINCR: case POSTINCR:
case POSTDECR: case POSTDECR:
case PLUSPLUS: case PLUSPLUS:
case MINMIN: case MINMIN:
/* i++; is parsed as i = i + 1; esp_l = expr2state(left, RVAL, USED);
* This isn't quite correct :
* The first statement doesn't USE i,
* the second does.
*/
esp1 = lint_expr(left, RVAL, USED);
esp2 = lint_expr(left, LVAL, USED);
check_and_merge(&esp1, esp2, oper);
if ( left->ex_class == Value
&& left->VL_CLASS == Name
) {
add_expr_state(left->EX_VALUE, SET, &esp1);
add_expr_state(left->EX_VALUE, USED, &esp1);
}
return esp1;
case '-': /* set resulting variable, if any */
case '*': if (ISNAME(left)) {
if (left == 0) /* unary */ change_state(left->VL_IDF, SET);
return lint_expr(right, RVAL, USED); add_expr_state(left->EX_VALUE, SET, &esp_l);
esp1 = lint_expr(left, RVAL, USED); }
esp2 = lint_expr(right, RVAL, USED);
check_and_merge(&esp1, esp2, oper); return esp_l;
return esp1;
case '?':
esp_l = expr2state(left, RVAL, USED);
esp_r = expr2state(right->OP_LEFT, RVAL, USED);
check_and_merge(expr, &esp_l, esp_r);
esp_r = expr2state(right->OP_RIGHT, RVAL, USED);
check_and_merge(expr, &esp_l, esp_r);
return esp_l;
case '(': case '(':
if (right != 0) { if (right != 0) {
@ -217,17 +204,15 @@ lint_oper(expr, val, used)
while ( ex->ex_class == Oper while ( ex->ex_class == Oper
&& ex->OP_OPER == PARCOMMA && ex->OP_OPER == PARCOMMA
) { ) {
esp2 = lint_expr(ex->OP_RIGHT, RVAL, esp_r = expr2state(ex->OP_RIGHT, RVAL, USED);
USED); check_and_merge(expr, &esp_l, esp_r);
check_and_merge(&esp1, esp2, oper);
ex = ex->OP_LEFT; ex = ex->OP_LEFT;
} }
esp2 = lint_expr(ex, RVAL, USED); esp_r = expr2state(ex, RVAL, USED);
check_and_merge(&esp1, esp2, oper); check_and_merge(expr, &esp_l, esp_r);
} }
if ( left->ex_class == Value
&& left->VL_CLASS == Name if (ISNAME(left)) {
) {
fill_outcall(expr, fill_outcall(expr,
expr->ex_type->tp_fund == VOID ? expr->ex_type->tp_fund == VOID ?
VOIDED : used VOIDED : used
@ -236,35 +221,34 @@ lint_oper(expr, val, used)
left->VL_IDF->id_def->df_used = 1; left->VL_IDF->id_def->df_used = 1;
} }
else { else {
esp2 = lint_expr(left, val, USED); esp_r = expr2state(left, RVAL, USED);
check_and_merge(&esp1, esp2, oper); check_and_merge(expr, &esp_l, esp_r);
} }
return esp1; referred_esp(esp_l);
return esp_l;
case '.': case '.':
return lint_expr(left, val, USED); return expr2state(left, val, USED);
case ARROW: case ARROW:
return lint_expr(left, RVAL, USED); return expr2state(left, RVAL, USED);
case '~':
case '!':
return lint_expr(right, RVAL, USED);
case '?':
esp1 = lint_expr(left, RVAL, USED);
esp2 = lint_expr(right->OP_LEFT, RVAL, USED);
check_and_merge(&esp1, esp2, 0);
esp2 = lint_expr(right->OP_RIGHT, RVAL, USED);
check_and_merge(&esp1, esp2, 0);
return esp1;
case INT2INT: case INT2INT:
case INT2FLOAT: case INT2FLOAT:
case FLOAT2INT: case FLOAT2INT:
case FLOAT2FLOAT: case FLOAT2FLOAT:
return lint_expr(right, RVAL, USED); return expr2state(right, RVAL, USED);
/* monadic operators */
case '-':
case '*':
if (left)
goto dyadic;
case '~':
case '!':
return expr2state(right, RVAL, USED);
/* relational operators */
case '<': case '<':
case '>': case '>':
case LESSEQ: case LESSEQ:
@ -279,7 +263,10 @@ lint_oper(expr, val, used)
oper == GREATEREQ ? LESSEQ : oper == GREATEREQ ? LESSEQ :
oper oper
); );
/*FALLTHROUGH*/ goto dyadic;
/* dyadic operators */
dyadic:
case '+': case '+':
case '/': case '/':
case '%': case '%':
@ -291,21 +278,20 @@ lint_oper(expr, val, used)
case '^': case '^':
case OR: case OR:
case AND: case AND:
esp1 = lint_expr(left, RVAL, esp_l = expr2state(left, RVAL,
oper == ',' ? IGNORED : USED); oper == ',' ? IGNORED : USED);
esp2 = lint_expr(right, RVAL, esp_r = expr2state(right, RVAL,
oper == ',' ? used : USED); oper == ',' ? used : USED);
if (oper == OR || oper == AND || oper == ',') check_and_merge(expr, &esp_l, esp_r);
check_and_merge(&esp1, esp2, 0);
else return esp_l;
check_and_merge(&esp1, esp2, oper);
return esp1;
default: default:
return 0; /* for initcomma */ return 0; /* for initcomma */
} }
} }
PRIVATE
expr_ignored(expr) expr_ignored(expr)
struct expr *expr; struct expr *expr;
{ {
@ -334,7 +320,7 @@ expr_ignored(expr)
case POSTDECR: case POSTDECR:
case PLUSPLUS: case PLUSPLUS:
case MINMIN: case MINMIN:
/* may hide the operator * */ /* may hide the operator '*' */
if ( /* operation on a pointer */ if ( /* operation on a pointer */
expr->OP_TYPE->tp_fund == POINTER expr->OP_TYPE->tp_fund == POINTER
&& /* the result is dereferenced, e.g. *p++; */ && /* the result is dereferenced, e.g. *p++; */
@ -361,4 +347,96 @@ expr_ignored(expr)
} }
} }
PRIVATE
add_expr_state(value, to_state, espp)
struct value value;
struct expr_state **espp;
{
register struct expr_state *esp = *espp;
ASSERT(value.vl_class == Name);
/* try to find the esp */
while ( esp
&& !( esp->es_idf == value.vl_data.vl_idf
&& esp->es_offset == value.vl_value
)
) {
esp = esp->next;
}
/* if not found, add it */
if (!esp) {
esp = new_expr_state();
esp->es_idf = value.vl_data.vl_idf;
esp->es_offset = value.vl_value;
esp->next = *espp;
*espp = esp;
}
/* set state */
switch (to_state) {
case USED:
esp->es_used = 1;
break;
case REFERRED:
esp->es_referred = 1;
break;
case SET:
esp->es_set = 1;
break;
default:
NOTREACHED();
/* NOTREACHED */
}
}
PRIVATE
referred_esp(esp)
struct expr_state *esp;
{
/* raises all REFERRED items to SET and USED status */
while (esp) {
if (esp->es_referred) {
esp->es_set = 1;
change_state(esp->es_idf, SET);
esp->es_used = 1;
change_state(esp->es_idf, USED);
esp->es_referred = 0;
}
esp = esp->next;
}
}
PRIVATE
free_expr_states(esp)
register struct expr_state *esp;
{
while (esp) {
register struct expr_state *esp2 = esp;
esp = esp->next;
free_expr_state(esp2);
}
}
#ifdef DEBUG
print_esp(msg, esp)
char *msg;
struct expr_state *esp;
{
print("%s: <", msg);
while (esp) {
print(" %s[%d]%c%c%c ",
esp->es_idf->id_text, esp->es_offset,
(esp->es_used ? 'U' : ' '),
(esp->es_referred ? 'R' : ' '),
(esp->es_set ? 'S' : ' ')
);
esp = esp->next;
}
print(">\n");
}
#endif DEBUG
#endif LINT #endif LINT

View file

@ -9,6 +9,7 @@
#define IGNORED 1 #define IGNORED 1
#define SET 2 #define SET 2
#define VOIDED 3 #define VOIDED 3
#define REFERRED 4
/* for od_valreturned */ /* for od_valreturned */
#define NOVALRETURNED 0 #define NOVALRETURNED 0

View file

@ -10,6 +10,7 @@
#ifdef LINT #ifdef LINT
#include <alloc.h> /* for st_free */ #include <alloc.h> /* for st_free */
#include "interface.h"
#include "arith.h" /* definition arith */ #include "arith.h" /* definition arith */
#include "label.h" /* definition label */ #include "label.h" /* definition label */
#include "expr.h" #include "expr.h"
@ -27,6 +28,10 @@
extern char *symbol2str(); extern char *symbol2str();
extern struct type *func_type; extern struct type *func_type;
PRIVATE lint_enum_arith();
PRIVATE lint_conversion();
PRIVATE int numsize();
lint_new_oper(expr) lint_new_oper(expr)
struct expr *expr; struct expr *expr;
{ {
@ -210,6 +215,7 @@ lint_new_oper(expr)
} }
} }
PRIVATE
lint_enum_arith(l_fund, oper, r_fund) lint_enum_arith(l_fund, oper, r_fund)
int l_fund, oper, r_fund; int l_fund, oper, r_fund;
{ {
@ -228,10 +234,11 @@ lint_enum_arith(l_fund, oper, r_fund)
&& l_fund != INT && l_fund != INT
) { ) {
warning("%s on %s and enum", warning("%s on %s and enum",
symbol2str(oper), symbol2str(r_fund)); symbol2str(oper), symbol2str(l_fund));
} }
} }
PRIVATE
lint_conversion(from_expr, to_fund) lint_conversion(from_expr, to_fund)
struct expr *from_expr; struct expr *from_expr;
int to_fund; int to_fund;
@ -267,7 +274,7 @@ lint_conversion(from_expr, to_fund)
} }
} }
int PRIVATE int
numsize(fund) numsize(fund)
{ {
switch (fund) { switch (fund) {

View file

@ -10,6 +10,7 @@
#ifdef LINT #ifdef LINT
#include <alloc.h> #include <alloc.h>
#include "interface.h"
#include "arith.h" #include "arith.h"
#include "assert.h" #include "assert.h"
#include "type.h" #include "type.h"
@ -33,7 +34,18 @@ extern char *bts2str();
extern char *symbol2str(); extern char *symbol2str();
int stat_number = 9999; /* static scope number */ int stat_number = 9999; /* static scope number */
struct outdef OutDef, OutCall; struct outdef OutDef;
PRIVATE struct outdef OutCall;
PRIVATE local_EFDC();
PRIVATE output_def();
PRIVATE outargs();
PRIVATE outarg();
PRIVATE outargstring();
PRIVATE outargtype();
PRIVATE implicit_func_decl();
PRIVATE fill_arg();
lint_declare_idf(idf, sc) lint_declare_idf(idf, sc)
struct idf *idf; struct idf *idf;
@ -111,6 +123,7 @@ set_od_valreturned(n)
OutDef.od_valreturned = n; OutDef.od_valreturned = n;
} }
PRIVATE
local_EFDC(idf) local_EFDC(idf)
struct idf *idf; struct idf *idf;
{ {
@ -251,6 +264,7 @@ outcall()
output_def(&OutCall); output_def(&OutCall);
} }
PRIVATE
output_def(od) output_def(od)
struct outdef *od; struct outdef *od;
{ {
@ -319,6 +333,7 @@ output_def(od)
printf(":%u:%s\n", od->od_line, od->od_file); printf(":%u:%s\n", od->od_line, od->od_file);
} }
PRIVATE
outargs(arg, n) outargs(arg, n)
struct argument *arg; struct argument *arg;
{ {
@ -341,6 +356,7 @@ outargs(arg, n)
} }
} }
PRIVATE
outarg(arg) outarg(arg)
struct argument *arg; struct argument *arg;
{ {
@ -379,6 +395,7 @@ outarg(arg)
} }
} }
PRIVATE
outargstring(arg) outargstring(arg)
struct argument *arg; struct argument *arg;
{ {
@ -393,6 +410,7 @@ outargstring(arg)
printf("\"%s\"", buff); printf("\"%s\"", buff);
} }
PRIVATE
outargtype(tp) outargtype(tp)
struct type *tp; struct type *tp;
{ {
@ -436,6 +454,7 @@ outargtype(tp)
} }
} }
PRIVATE
implicit_func_decl(idf, file, line) implicit_func_decl(idf, file, line)
struct idf *idf; struct idf *idf;
char *file; char *file;
@ -485,6 +504,7 @@ fill_outcall(ex, used)
OutCall.od_valused = used; /* USED, IGNORED or VOIDED */ OutCall.od_valused = used; /* USED, IGNORED or VOIDED */
} }
PRIVATE
fill_arg(e) fill_arg(e)
struct expr *e; struct expr *e;
{ {

View file

@ -66,6 +66,7 @@ struct expr_state {
struct idf *es_idf; struct idf *es_idf;
arith es_offset; arith es_offset;
int es_used; int es_used;
int es_referred;
int es_set; int es_set;
}; };

View file

@ -10,7 +10,9 @@
#ifdef LINT #ifdef LINT
#include <alloc.h> /* for st_free */ #include <alloc.h> /* for st_free */
#include "interface.h"
#include "assert.h" #include "assert.h"
#include "debug.h"
#include "arith.h" /* definition arith */ #include "arith.h" /* definition arith */
#include "label.h" /* definition label */ #include "label.h" /* definition label */
#include "expr.h" #include "expr.h"
@ -38,15 +40,29 @@ extern int func_notypegiven;
extern char loptions[]; extern char loptions[];
/* global variables for the lint_stack */ /* global variables for the lint_stack */
struct lint_stack_entry stack_bottom; PRIVATE struct lint_stack_entry stack_bottom;
struct lint_stack_entry *top_ls = &stack_bottom; PRIVATE struct lint_stack_entry *top_ls = &stack_bottom;
/* global variables for the brace stack */ /* global variables for the brace stack */
int brace_count; PRIVATE int brace_count;
struct brace brace_bottom; PRIVATE struct brace brace_bottom;
struct brace *top_br = &brace_bottom; PRIVATE struct brace *top_br = &brace_bottom;
static print_autos(); PRIVATE end_brace();
PRIVATE lint_1_local();
PRIVATE lint_1_global();
PRIVATE check_autos();
PRIVATE struct auto_def *copy_st_auto_list();
PRIVATE free_st_auto_list();
PRIVATE struct state *copy_state();
PRIVATE Free_state();
PRIVATE remove_settings();
PRIVATE struct auto_def *merge_autos();
PRIVATE merge_states();
PRIVATE struct lint_stack_entry *find_wdf(), *find_wdfc(), *find_cs();
PRIVATE cont_break_merge();
PRIVATE lint_push();
PRIVATE lint_pop();
lint_init_stack() lint_init_stack()
{ {
@ -90,6 +106,7 @@ lint_local_level(stl)
end_brace(stl); end_brace(stl);
} }
PRIVATE
end_brace(stl) end_brace(stl)
struct stack_level *stl; struct stack_level *stl;
{ {
@ -113,6 +130,7 @@ end_brace(stl)
free_brace(br); free_brace(br);
} }
PRIVATE
lint_1_local(idf, def) lint_1_local(idf, def)
struct idf *idf; struct idf *idf;
struct def *def; struct def *def;
@ -158,6 +176,7 @@ lint_global_level(stl)
} }
} }
PRIVATE
lint_1_global(idf, def) lint_1_global(idf, def)
struct idf *idf; struct idf *idf;
struct def *def; struct def *def;
@ -219,6 +238,7 @@ lint_1_global(idf, def)
change_state(idf, to_state) change_state(idf, to_state)
struct idf *idf; struct idf *idf;
int to_state; /* SET or USED */
{ {
/* Changes the state of the variable identified by idf in the current state /* Changes the state of the variable identified by idf in the current state
* on top of the stack. * on top of the stack.
@ -228,10 +248,14 @@ change_state(idf, to_state)
register struct auto_def *a = top_ls->ls_current->st_auto_list; register struct auto_def *a = top_ls->ls_current->st_auto_list;
if (def) { if (def) {
if (to_state == SET) switch (to_state) {
case SET:
def->df_set = 1; def->df_set = 1;
else break;
case USED:
def->df_used = 1; def->df_used = 1;
break;
}
if (def->df_firstbrace == 0) { if (def->df_firstbrace == 0) {
def->df_firstbrace = brace_count; def->df_firstbrace = brace_count;
@ -256,20 +280,22 @@ change_state(idf, to_state)
if (a == 0) /* identifier not in list */ if (a == 0) /* identifier not in list */
return; return;
if (to_state == SET) { switch (to_state) {
case SET:
a->ad_maybe_set = 0; a->ad_maybe_set = 0;
a->ad_set = 1; a->ad_set = 1;
return; break;
case USED:
if (!a->ad_set) {
warning("%s%s uninitialized", idf->id_text,
(a->ad_maybe_set ? " possibly" : "")
);
a->ad_maybe_set = 0;
a->ad_set = 1; /* one warning */
}
a->ad_used = 1;
break;
} }
/* else to_state == USED */
if (!a->ad_set) {
warning("%s%s uninitialized", idf->id_text,
(a->ad_maybe_set ? " possibly" : "")
);
a->ad_maybe_set = 0;
a->ad_set = 1; /* one warning */
}
a->ad_used = 1;
} }
extern struct stack_level *local_level; extern struct stack_level *local_level;
@ -301,6 +327,7 @@ add_auto(idf) /* to current state on top of lint_stack */
} }
} }
PRIVATE
check_autos() check_autos()
{ {
/* Before leaving a block remove the auto_defs of the automatic /* Before leaving a block remove the auto_defs of the automatic
@ -348,7 +375,7 @@ check_args_used()
} }
} }
struct auto_def * PRIVATE struct auto_def *
copy_st_auto_list(from_al, lvl) copy_st_auto_list(from_al, lvl)
struct auto_def *from_al; struct auto_def *from_al;
{ {
@ -370,6 +397,7 @@ copy_st_auto_list(from_al, lvl)
return start; return start;
} }
PRIVATE
free_st_auto_list(au) free_st_auto_list(au)
register struct auto_def *au; register struct auto_def *au;
{ {
@ -382,7 +410,7 @@ free_st_auto_list(au)
} }
} }
struct state * PRIVATE struct state *
copy_state(from_st, lvl) copy_state(from_st, lvl)
struct state *from_st; struct state *from_st;
{ {
@ -397,7 +425,7 @@ copy_state(from_st, lvl)
return st; return st;
} }
static PRIVATE
Free_state(stp) Free_state(stp)
struct state **stp; struct state **stp;
{ {
@ -408,6 +436,7 @@ Free_state(stp)
*stp = 0; *stp = 0;
} }
PRIVATE
remove_settings(state, lvl) remove_settings(state, lvl)
struct state *state; struct state *state;
{ {
@ -430,7 +459,7 @@ remove_settings(state, lvl)
#define CASE_BREAK 1 #define CASE_BREAK 1
#define USE_ONLY 2 #define USE_ONLY 2
struct auto_def * PRIVATE struct auto_def *
merge_autos(a1, a2, lvl, mode) merge_autos(a1, a2, lvl, mode)
struct auto_def *a1, *a2; struct auto_def *a1, *a2;
int mode; int mode;
@ -491,6 +520,7 @@ merge_autos(a1, a2, lvl, mode)
return a; return a;
} }
PRIVATE
merge_states(st1, st2, lvl, mode) merge_states(st1, st2, lvl, mode)
struct state *st1, *st2; struct state *st1, *st2;
int mode; int mode;
@ -532,7 +562,7 @@ merge_states(st1, st2, lvl, mode)
* The letters mean : w: WHILE; d: DO; f: FOR; s: SWITCH; c: CASE. * The letters mean : w: WHILE; d: DO; f: FOR; s: SWITCH; c: CASE.
*/ */
struct lint_stack_entry * PRIVATE struct lint_stack_entry *
find_wdf() find_wdf()
{ {
register struct lint_stack_entry *lse = top_ls; register struct lint_stack_entry *lse = top_ls;
@ -549,7 +579,7 @@ find_wdf()
return 0; return 0;
} }
struct lint_stack_entry * PRIVATE struct lint_stack_entry *
find_wdfc() find_wdfc()
{ {
register struct lint_stack_entry *lse = top_ls; register struct lint_stack_entry *lse = top_ls;
@ -567,7 +597,7 @@ find_wdfc()
return 0; return 0;
} }
struct lint_stack_entry * PRIVATE struct lint_stack_entry *
find_cs() find_cs()
{ {
register struct lint_stack_entry *lse = top_ls; register struct lint_stack_entry *lse = top_ls;
@ -691,6 +721,7 @@ end_do_stmt(const, cond)
} }
} }
PRIVATE
cont_break_merge(lse) cont_break_merge(lse)
struct lint_stack_entry *lse; struct lint_stack_entry *lse;
{ {
@ -988,7 +1019,7 @@ lint_statement()
return; return;
if (top_ls->ls_current->st_notreached) { if (top_ls->ls_current->st_notreached) {
if (DOT != CASE && DOT != DEFAULT && AHEAD != ':') { if (DOT != CASE && DOT != DEFAULT && AHEAD != ':') {
if (DOT != BREAK || !loptions['b']) if (DOT != BREAK || loptions['b'])
warning("statement cannot be reached"); warning("statement cannot be reached");
top_ls->ls_current->st_warned = 1; top_ls->ls_current->st_warned = 1;
} }
@ -999,6 +1030,7 @@ lint_statement()
} }
} }
PRIVATE
lint_push(lse) lint_push(lse)
struct lint_stack_entry *lse; struct lint_stack_entry *lse;
{ {
@ -1007,13 +1039,14 @@ lint_push(lse)
top_ls = lse; top_ls = lse;
} }
PRIVATE
lint_pop() lint_pop()
{ {
top_ls = top_ls->ls_previous; top_ls = top_ls->ls_previous;
free_lint_stack_entry(top_ls->next); free_lint_stack_entry(top_ls->next);
} }
#ifdef DEBUG
/* FOR DEBUGGING */ /* FOR DEBUGGING */
print_lint_stack() print_lint_stack()
@ -1082,7 +1115,6 @@ print_lint_stack()
print(" |--------------\n\n"); print(" |--------------\n\n");
} }
static
print_autos(a) print_autos(a)
register struct auto_def *a; register struct auto_def *a;
{ {
@ -1094,4 +1126,6 @@ print_autos(a)
} }
print("\n"); print("\n");
} }
#endif DEBUG
#endif LINT #endif LINT