From: dick Date: Mon, 6 Mar 1989 15:17:39 +0000 (+0000) Subject: more lint code X-Git-Tag: release-5-5~2529 X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=1d0b3910b2553d237df7b2547e060f0355a38b7f;p=ack.git more lint code --- diff --git a/lang/cem/cemcom/Makefile b/lang/cem/cemcom/Makefile index b964ac109..9a87abdd9 100644 --- a/lang/cem/cemcom/Makefile +++ b/lang/cem/cemcom/Makefile @@ -929,7 +929,6 @@ declar.o: field.h declar.o: file_info.h declar.o: idf.h declar.o: l_lint.h -declar.o: l_state.h declar.o: label.h declar.o: level.h declar.o: lint.h @@ -953,7 +952,6 @@ statement.o: expr.h statement.o: file_info.h statement.o: idf.h statement.o: l_lint.h -statement.o: l_state.h statement.o: label.h statement.o: lint.h statement.o: nobitfield.h @@ -986,7 +984,7 @@ program.o: def.h program.o: expr.h program.o: file_info.h program.o: idf.h -program.o: l_state.h +program.o: l_lint.h program.o: label.h program.o: lint.h program.o: nobitfield.h diff --git a/lang/cem/cemcom/ch7bin.c b/lang/cem/cemcom/ch7bin.c index 0225351ee..72ee4ace7 100644 --- a/lang/cem/cemcom/ch7bin.c +++ b/lang/cem/cemcom/ch7bin.c @@ -280,10 +280,15 @@ ch7bin(expp, oper, expr) break; case ',': - if (is_cp_cst(*expp)) + if (is_cp_cst(*expp)) { +#ifdef LINT + hwarning("constant expression ignored"); +#endif LINT *expp = expr; - else + } + else { *expp = new_oper(expr->ex_type, *expp, oper, expr); + } (*expp)->ex_flags |= EX_COMMA; break; } diff --git a/lang/cem/cemcom/declar.g b/lang/cem/cemcom/declar.g index 92a501ea0..c14676c44 100644 --- a/lang/cem/cemcom/declar.g +++ b/lang/cem/cemcom/declar.g @@ -27,7 +27,6 @@ #include "level.h" #ifdef LINT #include "l_lint.h" -#include "l_state.h" #endif LINT extern char options[]; diff --git a/lang/cem/cemcom/idf.c b/lang/cem/cemcom/idf.c index e648e8327..64d4abbeb 100644 --- a/lang/cem/cemcom/idf.c +++ b/lang/cem/cemcom/idf.c @@ -353,7 +353,7 @@ declare_idf(ds, dc, lvl) newdef->df_file = idf->id_file; newdef->df_line = idf->id_line; #ifdef LINT - newdef->df_set = (type->tp_fund == ARRAY); + newdef->df_set = 0; newdef->df_firstbrace = 0; #endif LINT @@ -490,11 +490,17 @@ global_redecl(idf, new_sc, tp) error("cannot redeclare %s to static", idf->id_text); else { +#ifdef LINT /* warn unconditionally */ + warning("%s redeclared to static", + idf->id_text); +#else LINT #ifndef NOROPTION + /* warn conditionally */ if (options['R']) warning("%s redeclared to static", idf->id_text); -#endif +#endif NOROPTION +#endif LINT def->df_sc = STATIC; } break; diff --git a/lang/cem/cemcom/l_lint.c b/lang/cem/cemcom/l_lint.c index b591e11f3..f8d0de902 100644 --- a/lang/cem/cemcom/l_lint.c +++ b/lang/cem/cemcom/l_lint.c @@ -255,14 +255,6 @@ oper2state(expr, val, used) case GREATEREQ: case EQUAL: case NOTEQUAL: - lint_relop(left, right, oper); - lint_relop(right, left, - oper == '<' ? '>' : - oper == '>' ? '<' : - oper == LESSEQ ? GREATEREQ : - oper == GREATEREQ ? LESSEQ : - oper - ); goto dyadic; /* dyadic operators */ @@ -338,11 +330,16 @@ expr_ignored(expr) break; case Value: - hwarning("value as statement"); + if (expr->VL_CLASS == Const) { + hwarning("constant expression ignored"); + } + else { + hwarning("value ignored"); + } break; default: /* String Float */ - hwarning("constant as statement"); + hwarning("constant ignored"); break; } } diff --git a/lang/cem/cemcom/l_state.str b/lang/cem/cemcom/l_state.str index 2ef91912b..5f8f1b281 100644 --- a/lang/cem/cemcom/l_state.str +++ b/lang/cem/cemcom/l_state.str @@ -12,35 +12,52 @@ * control of the program. */ +#define TEST_VAR 0 /* not a constant */ +#define TEST_TRUE 1 /* always true */ +#define TEST_FALSE 2 /* always false */ -struct switch_states { +struct loop_state { /* used in lint_end_state only */ + int lps_test; /* is the test a constant? */ + struct state *lps_body; + struct state *lps_loop; +}; + +struct switch_state { /* used in lint_end_state only */ struct state *sws_case; struct state *sws_break; int sws_default_met; }; +/* This union describes the (possibly incomplete) state at the end of the + mentioned construct. +*/ +union lint_end_state { /* used in lint_stack_entry only */ + struct state *ule_if; + struct loop_state ule_loop; + struct switch_state ule_switch; +}; + struct lint_stack_entry { struct lint_stack_entry *next; struct lint_stack_entry *ls_previous; - short ls_class; /* IF, WHILE, DO, FOR, SWITCH, CASE */ int ls_level; - struct state *ls_current; /* used by all classes */ - union { - struct state *u_if_state; /* used for IF-class */ - struct state *u_end; /* used for loop-classes */ - struct switch_states u_switch; - } ls_states; /* not used for CASE-class */ + struct state *ls_current; /* used by all classes */ + short ls_class; /* IF, WHILE, DO, FOR, SWITCH, CASE */ + union lint_end_state ls_end; }; -/* macros to access the union */ -#define LS_IF_STATE ls_states.u_if_state -#define LS_END ls_states.u_end -#define LS_CASE ls_states.u_switch.sws_case -#define LS_BREAK ls_states.u_switch.sws_break -#define LS_DEFAULT_MET ls_states.u_switch.sws_default_met - /* ALLOCDEF "lint_stack_entry" 10 */ +/* macros to access the union */ +#define LS_IF ls_end.ule_if +#define LS_TEST ls_end.ule_loop.lps_test +#define LS_BODY ls_end.ule_loop.lps_body +#define LS_LOOP ls_end.ule_loop.lps_loop +#define LS_CASE ls_end.ule_switch.sws_case +#define LS_BREAK ls_end.ule_switch.sws_break +#define LS_DEFAULT_MET ls_end.ule_switch.sws_default_met + +/* describes a branch in the program, with its local idfs */ struct state { struct state *next; /* only used by memory allocator */ struct auto_def *st_auto_list; @@ -50,6 +67,7 @@ struct state { /* ALLOCDEF "state" 15 */ +/* describes the state of a local idf in a given branch of the program */ struct auto_def { struct auto_def *next; struct idf *ad_idf; @@ -61,13 +79,14 @@ struct auto_def { /* ALLOCDEF "auto_def" 20 */ -struct expr_state { +/* describes the state of an idf during expression evaluation */ +struct expr_state { /*actually concerns idfs only */ struct expr_state *next; - struct idf *es_idf; + struct idf *es_idf; /* the idf with its offset */ arith es_offset; - int es_used; - int es_referred; - int es_set; + int es_used; /* value has been used */ + int es_referred; /* address has been taken */ + int es_set; /* has been assigned to */ }; /* ALLOCDEF "expr_state" 20 */ diff --git a/lang/cem/cemcom/l_states.c b/lang/cem/cemcom/l_states.c index ad47b97fa..78c486089 100644 --- a/lang/cem/cemcom/l_states.c +++ b/lang/cem/cemcom/l_states.c @@ -13,8 +13,8 @@ #include "interface.h" #include "assert.h" #include "debug.h" -#include "arith.h" /* definition arith */ -#include "label.h" /* definition label */ +#include "arith.h" +#include "label.h" #include "expr.h" #include "idf.h" #include "def.h" @@ -31,50 +31,62 @@ #include "l_comment.h" #include "l_outdef.h" -#define min(a, b) ((a) < (b) ? (a) : (b)) +#ifdef DEBUG +#define dbg_lint_stack(m) /*print_lint_stack(m) /* or not */ +#else +#define dbg_lint_stack(m) +#endif DEBUG extern char *symbol2str(); extern char *func_name; extern struct type *func_type; extern int func_notypegiven; extern char loptions[]; +extern struct stack_level *local_level; /* global variables for the lint_stack */ -PRIVATE struct lint_stack_entry stack_bottom; -PRIVATE struct lint_stack_entry *top_ls = &stack_bottom; +PRIVATE struct lint_stack_entry *top_ls; /* global variables for the brace stack */ PRIVATE int brace_count; -PRIVATE struct brace brace_bottom; -PRIVATE struct brace *top_br = &brace_bottom; +PRIVATE struct brace *top_br; + +/* global variables for the function return */ +PRIVATE int valreturned; /* see l_lint.h */ +PRIVATE int return_warned; PRIVATE end_brace(); PRIVATE lint_1_local(); PRIVATE lint_1_global(); +PRIVATE start_loop_stmt(); PRIVATE check_autos(); -PRIVATE struct auto_def *copy_st_auto_list(); -PRIVATE free_st_auto_list(); +PRIVATE struct auto_def *copy_auto_list(); +PRIVATE free_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 cont_merge(); +PRIVATE break_merge(); +PRIVATE struct lint_stack_entry *mk_lint_stack_entry(); PRIVATE lint_push(); PRIVATE lint_pop(); lint_init_stack() { -/* Allocate some memory for the global stack_bottom - */ - stack_bottom.ls_current = new_state(); +/* Allocate memory for the global lint-stack elements. +*/ + top_ls = new_lint_stack_entry(); + top_ls->ls_current = new_state(); } lint_start_local() { register struct brace *br = new_brace(); + dbg_lint_stack("lint_start_local"); brace_count++; br->br_count = brace_count; br->br_level = level; @@ -82,24 +94,20 @@ lint_start_local() top_br = br; } -lint_local_level(stl) +lint_end_local(stl) struct stack_level *stl; { + + dbg_lint_stack("lint_end_local"); if (s_NOTREACHED) { top_ls->ls_current->st_notreached = 1; + top_ls->ls_current->st_warned = 0; s_NOTREACHED = 0; } if (top_ls->ls_class == CASE && level == top_ls->ls_level) { + /* supply missing break; at end of switch */ lint_break_stmt(); - /* To prevent a warning for the case - * switch (cond) { - * int i; - * case 0: - * i = 0; - * use(i); - * } - */ } check_autos(); @@ -111,6 +119,7 @@ end_brace(stl) struct stack_level *stl; { /* Check if static variables and labels are used and/or set. + Automatic vars have already been checked by check_autos(). */ register struct stack_entry *se = stl->sl_entry; register struct brace *br; @@ -125,6 +134,7 @@ end_brace(stl) se = se->next; } + /* remove entry from brace stack */ br = top_br; top_br = br->next; free_brace(br); @@ -159,11 +169,12 @@ lint_1_local(idf, def) } } -lint_global_level(stl) +lint_end_global(stl) struct stack_level *stl; { register struct stack_entry *se = stl->sl_entry; + dbg_lint_stack("lint_end_global"); ASSERT(level == L_GLOBAL); while (se) { register struct idf *idf = se->se_idf; @@ -198,38 +209,38 @@ lint_1_global(idf, def) */ output_use(idf); } - else { - if (sc == STATIC) { - if (def->df_set) { - def_warning(def, - "%s %s %s set but not used", - symbol2str(sc), - symbol2str(fund), - idf->id_text); - } - else { - def_warning(def, - "%s %s %s not used anywhere", - symbol2str(sc), - symbol2str(fund), - idf->id_text); - } + + if (sc == STATIC && !def->df_used) { + if (def->df_set) { + def_warning(def, + "%s %s %s set but not used", + symbol2str(sc), + symbol2str(fund), + idf->id_text); + } + else { + def_warning(def, + "%s %s %s not used anywhere", + symbol2str(sc), + symbol2str(fund), + idf->id_text); } - if (loptions['x']) { - register char *fn = def->df_file; - - if ( (sc == EXTERN || sc == GLOBAL) - && def->df_alloc == 0 - && !def->df_set - && !def->df_initialized - && strcmp(&fn[strlen(fn)-2], ".c") == 0 - ) { - def_warning(def, - "%s %s %s not used anywhere", - symbol2str(sc), - symbol2str(fund), - idf->id_text); - } + } + if (loptions['x']) { + register char *fn = def->df_file; + + if ( (sc == EXTERN || sc == GLOBAL) + && def->df_alloc == 0 + && !def->df_set + && !def->df_initialized + && !def->df_used + && strcmp(&fn[strlen(fn)-2], ".c") == 0 + ) { + def_warning(def, + "%s %s %s not used anywhere", + symbol2str(sc), + symbol2str(fund), + idf->id_text); } } break; @@ -242,42 +253,44 @@ change_state(idf, to_state) { /* Changes the state of the variable identified by idf in the current state * on top of the stack. - * For non-automatic variables, the fields in the def-descriptor are set too. + * The fields in the def-descriptor are set too. */ register struct def *def = idf->id_def; register struct auto_def *a = top_ls->ls_current->st_auto_list; - if (def) { - switch (to_state) { - case SET: - def->df_set = 1; - break; - case USED: - def->df_used = 1; - break; - } + ASSERT(def); - if (def->df_firstbrace == 0) { - def->df_firstbrace = brace_count; - def->df_minlevel = level; - } - else { - register struct brace *br = top_br; + switch (to_state) { + case SET: + def->df_set = 1; + break; + case USED: + def->df_used = 1; + break; + } - /* find the smallest brace range from which - firstbrace is visible - */ - while (br && br->br_count > def->df_firstbrace) { - br = br->next; - } - ASSERT(br && def->df_minlevel >= br->br_level); - def->df_minlevel = br->br_level; + /* adjust minimum required brace level */ + if (def->df_firstbrace == 0) { + def->df_firstbrace = brace_count; + def->df_minlevel = level; + } + else { + register struct brace *br = top_br; + + /* find the smallest brace range from which + firstbrace is visible + */ + while (br && br->br_count > def->df_firstbrace) { + br = br->next; } + ASSERT(br && def->df_minlevel >= br->br_level); + def->df_minlevel = br->br_level; } + /* search auto_list */ while(a && a->ad_idf != idf) a = a->next; - if (a == 0) /* identifier not in list */ + if (a == 0) /* identifier not in list, global definition */ return; switch (to_state) { @@ -298,30 +311,31 @@ change_state(idf, to_state) } } -extern struct stack_level *local_level; - add_auto(idf) /* to current state on top of lint_stack */ struct idf *idf; { /* Check if idf's definition is really an auto (or register). * It could be a static or extern too. - * Watch out for register formal parameters. + * Watch out for formal parameters. */ register struct def *def = idf->id_def; - register struct auto_def *a; - if (!def) - return; + ASSERT(def); + switch (def->df_sc) { + register struct auto_def *a; case AUTO: case REGISTER: if (def->df_level < L_LOCAL) - return; /* a register formal */ + return; /* a formal */ + a = new_auto_def(); + a->ad_idf = idf; a->ad_def = idf->id_def; a->ad_used = def->df_used; a->ad_set = def->df_set; + a->next = top_ls->ls_current->st_auto_list; top_ls->ls_current->st_auto_list = a; } @@ -330,37 +344,40 @@ add_auto(idf) /* to current state on top of lint_stack */ PRIVATE check_autos() { -/* Before leaving a block remove the auto_defs of the automatic +/* Before leaving a block, remove the auto_defs of the automatic * variables on this level and check if they are used */ - register struct auto_def *a1 = top_ls->ls_current->st_auto_list; - register struct auto_def *a2; + register struct auto_def *a = top_ls->ls_current->st_auto_list; - ASSERT(!(a1 && a1->ad_def->df_level > level)); - while (a1 && a1->ad_def->df_level == level) { - a2 = a1; - a1 = a1->next; - if (!a2->ad_used) { - if (a2->ad_set || a2->ad_maybe_set) { - def_warning(a2->ad_def, + ASSERT(!(a && a->ad_def->df_level > level)); + while (a && a->ad_def->df_level == level) { + if (!a->ad_used) { + if (a->ad_set || a->ad_maybe_set) { + def_warning(a->ad_def, "%s set but not used in function %s", - a2->ad_idf->id_text, func_name); + a->ad_idf->id_text, func_name); } else { - def_warning(a2->ad_def, + def_warning(a->ad_def, "%s neither set nor used in function %s", - a2->ad_idf->id_text, func_name); + a->ad_idf->id_text, func_name); } } - free_auto_def(a2); + + { /* free a */ + register struct auto_def *aux = a; + a = a->next; + free_auto_def(aux); + } } - top_ls->ls_current->st_auto_list = a1; + top_ls->ls_current->st_auto_list = a; } -check_args_used() +lint_end_formals() { register struct stack_entry *se = local_level->sl_entry; + dbg_lint_stack("lint_end_formals"); ASSERT(level == L_FORMAL1); while (se) { register struct def *def = se->se_idf->id_def; @@ -376,15 +393,18 @@ check_args_used() } PRIVATE struct auto_def * -copy_st_auto_list(from_al, lvl) +copy_auto_list(from_al, lvl) struct auto_def *from_al; + int lvl; { struct auto_def *start = 0; register struct auto_def **hook = &start; + /* skip too high levels */ while (from_al && from_al->ad_def->df_level > lvl) { from_al = from_al->next; } + while (from_al) { register struct auto_def *a = new_auto_def(); @@ -398,28 +418,27 @@ copy_st_auto_list(from_al, lvl) } PRIVATE -free_st_auto_list(au) - register struct auto_def *au; -{ +free_auto_list(a) register struct auto_def *a; - - while (au) { - a = au; - au = au->next; - free_auto_def(a); +{ + while (a) { + register struct auto_def *aux = a; + a = a->next; + free_auto_def(aux); } } PRIVATE struct state * copy_state(from_st, lvl) struct state *from_st; + int lvl; { /* Memory for the struct state and the struct auto_defs is allocated * by this function */ register struct state *st = new_state(); - st->st_auto_list = copy_st_auto_list(from_st->st_auto_list, lvl); + st->st_auto_list = copy_auto_list(from_st->st_auto_list, lvl); st->st_notreached = from_st->st_notreached; st->st_warned = from_st->st_warned; return st; @@ -431,19 +450,20 @@ Free_state(stp) { /* This function also frees the list of auto_defs */ - free_st_auto_list((*stp)->st_auto_list); + free_auto_list((*stp)->st_auto_list); free_state(*stp); *stp = 0; } PRIVATE -remove_settings(state, lvl) - struct state *state; +remove_settings(st, lvl) + struct state *st; + int lvl; { -/* The state of all variables on this level are set to 'not set' and +/* The states of all variables on this level are set to 'not set' and * 'not maybe set'. (I think you have to read this twice.) */ - register struct auto_def *a = state->st_auto_list; + register struct auto_def *a = st->st_auto_list; while (a && a->ad_def->df_level == lvl) { a->ad_set = a->ad_maybe_set = 0; @@ -459,9 +479,48 @@ remove_settings(state, lvl) #define CASE_BREAK 1 #define USE_ONLY 2 +PRIVATE +merge_states(st1, st2, lvl, mode) + struct state *st1, *st2; + int lvl; + int mode; /* NORMAL or CASE_BREAK */ +{ +/* st2 becomes the result. + * st1 is left unchanged. + * The resulting state is the state the program gets in if st1 OR st2 + * becomes the state. (E.g. the states at the end of an if-part and an + * end-part are merged by this function.) + */ + if (st1->st_notreached) { + if (mode == NORMAL || st2->st_notreached) { + st2->st_auto_list = + merge_autos(st1->st_auto_list, + st2->st_auto_list, lvl, USE_ONLY); + } + } + else + if (st2->st_notreached) { + register struct auto_def *tmp = st2->st_auto_list; + + st2->st_auto_list = copy_auto_list(st1->st_auto_list, lvl); + st2->st_notreached = 0; + st2->st_warned = 0; + st2->st_auto_list = merge_autos(tmp, st2->st_auto_list, + lvl, USE_ONLY); + free_auto_list(tmp); + } + else { + /* both st1 and st2 reached */ + st2->st_auto_list = + merge_autos(st1->st_auto_list, st2->st_auto_list, + lvl, mode); + } +} + PRIVATE struct auto_def * merge_autos(a1, a2, lvl, mode) struct auto_def *a1, *a2; + int lvl; int mode; { /* Returns a pointer to the result. @@ -484,17 +543,23 @@ merge_autos(a1, a2, lvl, mode) */ register struct auto_def *a; + /* skip too local entries */ while (a1 && a1->ad_def->df_level > lvl) { a1 = a1->next; } + + /* discard too local entries */ while (a2 && a2->ad_def->df_level > lvl) { - a = a2; + register struct auto_def *aux = a2; a2 = a2->next; - free_auto_def(a); + free_auto_def(aux); } + a = a2; /* pointer to the result */ while (a1) { ASSERT(a2); + + /* merge the auto_defs for one idf */ ASSERT(a1->ad_idf == a2->ad_idf); if (a1->ad_used) a2->ad_used = 1; @@ -520,41 +585,6 @@ merge_autos(a1, a2, lvl, mode) return a; } -PRIVATE -merge_states(st1, st2, lvl, mode) - struct state *st1, *st2; - int mode; -{ -/* st2 becomes the result. - * st1 is left unchanged. - * The resulting state is the state the program gets in if st1 OR st2 - * becomes the state. (E.g. the states at the end of an if-part and an - * end-part are merged by this function.) - */ - if (st1->st_notreached) { - if (mode == NORMAL || st2->st_notreached) { - st2->st_auto_list = - merge_autos(st1->st_auto_list, - st2->st_auto_list, lvl, USE_ONLY); - } - } - else if (st2->st_notreached) { - register struct auto_def *tmp = st2->st_auto_list; - - st2->st_auto_list = copy_st_auto_list(st1->st_auto_list, lvl); - st2->st_notreached = 0; - st2->st_warned = 0; - st2->st_auto_list = merge_autos(tmp, st2->st_auto_list, - lvl, USE_ONLY); - free_st_auto_list(tmp); - } - else { - st2->st_auto_list = - merge_autos(st1->st_auto_list, st2->st_auto_list, - lvl, mode); - } -} - /******** L I N T S T A C K S E A R C H I N G ********/ @@ -567,7 +597,7 @@ find_wdf() { register struct lint_stack_entry *lse = top_ls; - while (lse != &stack_bottom) { + while (lse) { switch (lse->ls_class) { case WHILE: case DO: @@ -584,7 +614,7 @@ find_wdfc() { register struct lint_stack_entry *lse = top_ls; - while (lse != &stack_bottom) { + while (lse) { switch (lse->ls_class) { case WHILE: case DO: @@ -602,7 +632,7 @@ find_cs() { register struct lint_stack_entry *lse = top_ls; - while (lse != &stack_bottom) { + while (lse) { switch (lse->ls_class) { case CASE: case SWITCH: @@ -613,139 +643,198 @@ find_cs() return 0; } -/******** A C T I O N S ********/ +/******** A C T I O N S : I F ********/ start_if_part(const) { -/* Push a new stack entry on the lint_stack with class == IF - * copy the ls_current to the top of this stack - */ - register struct lint_stack_entry *lse = new_lint_stack_entry(); + register struct lint_stack_entry *new = mk_lint_stack_entry(IF); + dbg_lint_stack("start_if_part"); if (const) hwarning("condition in if statement is constant"); - lse->ls_class = IF; - lse->ls_current = copy_state(top_ls->ls_current, level); - lse->ls_level = level; - lint_push(lse); + lint_push(new); +/* ls_current: the state at the start of the if-part +*/ } start_else_part() { -/* Move ls_current to LS_IF_STATE - * ls_current of the stack entry one below is copied to ls_current. - */ +/* ls_current: the state at the end of the if-part + ls_previous->ls_current: the state before the if-part +*/ + + dbg_lint_stack("start_else_part"); if (s_NOTREACHED) { top_ls->ls_current->st_notreached = 1; + top_ls->ls_current->st_warned = 0; s_NOTREACHED = 0; } - top_ls->LS_IF_STATE = top_ls->ls_current; + top_ls->LS_IF = top_ls->ls_current; /* this is the reason why ls_current is a pointer */ - top_ls->ls_current = copy_state(top_ls->ls_previous->ls_current, - level); + top_ls->ls_current = + copy_state(top_ls->ls_previous->ls_current, level); top_ls->ls_level = level; +/* ls_current: the state before the if-part and the else-part + LS_IF: the state at the end of the if-part +*/ } end_if_else_stmt() { - Free_state(&top_ls->ls_previous->ls_current); - merge_states(top_ls->LS_IF_STATE, top_ls->ls_current, +/* ls_current: state at the end of the else-part + LS_IF: state at the end of the if-part +*/ + + dbg_lint_stack("end_if_else_stmt"); + merge_states(top_ls->LS_IF, top_ls->ls_current, top_ls->ls_level, NORMAL); - Free_state(&top_ls->LS_IF_STATE); + Free_state(&top_ls->LS_IF); + Free_state(&top_ls->ls_previous->ls_current); top_ls->ls_previous->ls_current = top_ls->ls_current; lint_pop(); } end_if_stmt() { -/* No else-part met; merge ls_current with ls_current of previous - * stack entry - */ +/* No else-part met. + ls_current: state at the end of the if-part +*/ + + dbg_lint_stack("end_if_stmt"); merge_states(top_ls->ls_current, top_ls->ls_previous->ls_current, top_ls->ls_level, NORMAL); Free_state(&top_ls->ls_current); lint_pop(); } +/******** A C T I O N S : L O O P S ********/ + +start_while_stmt(expr) + struct expr *expr; +{ + if (is_cp_cst(expr)) { + start_loop_stmt(WHILE, 1, expr->VL_VALUE != (arith)0); + } + else { + start_loop_stmt(WHILE, 0, 0); + } +} + +start_do_stmt() +{ + start_loop_stmt(DO, 1, 1); +} + +start_for_stmt(expr) + struct expr *expr; +{ + if (!expr) { + start_loop_stmt(FOR, 1, 1); + } + else + if (is_cp_cst(expr)) { + start_loop_stmt(FOR, 1, expr->VL_VALUE != (arith)0); + } + else { + start_loop_stmt(FOR, 0, 0); + } +} + +PRIVATE start_loop_stmt(looptype, const, cond) { -/* If const, the condition is constant and given in cond */ - register struct lint_stack_entry *lse = new_lint_stack_entry(); +/* If const, the condition is a constant and its value is cond +*/ + register struct lint_stack_entry *new = mk_lint_stack_entry(looptype); - lse->ls_class = looptype; - lse->ls_current = copy_state(top_ls->ls_current, level); - lse->ls_level = level; + dbg_lint_stack("start_loop_stmt"); if (const && !cond) { /* while (0) | for (;0;) */ hwarning("condition in %s statement is constant", symbol2str(looptype)); - lse->ls_current->st_notreached = 1; + new->ls_current->st_notreached = 1; } if (const && cond) { /* while (1) | for (;;) | do */ - /* omitting the copy for LS_END will force this loop + /* omitting the copy for LS_LOOP will force this loop to be treated as a do loop */ top_ls->ls_current->st_notreached = 1; + top_ls->ls_current->st_warned = 0; } else { - lse->LS_END = copy_state(top_ls->ls_current, level); + new->LS_LOOP = copy_state(top_ls->ls_current, level); } - lint_push(lse); + new->LS_TEST = (!const ? TEST_VAR : cond ? TEST_TRUE : TEST_FALSE); + lint_push(new); + +/* ls_current: the state at the start of the body + LS_TEST: info about the loop test + LS_BODY: 0, the state at the end of the body + LS_LOOP: the state at the end of the loop, or 0 if the loop + does not end +*/ } -end_loop_stmt() +end_loop_body() { - register struct lint_stack_entry *prev_ls = top_ls->ls_previous; + register struct lint_stack_entry *lse = find_wdf(); - lint_continue_stmt(); - top_ls->LS_END->st_notreached = prev_ls->ls_current->st_notreached; - top_ls->LS_END->st_warned = prev_ls->ls_current->st_warned; - Free_state(&top_ls->ls_current); - Free_state(&prev_ls->ls_current); - prev_ls->ls_current = top_ls->LS_END; - lint_pop(); + dbg_lint_stack("end_loop_body"); + ASSERT(lse == top_ls); + if (!lse->ls_current->st_notreached) + cont_merge(lse); } -end_do_stmt(const, cond) +end_loop_stmt() { - end_loop_stmt(); - if (const) - hwarning("condition in do-while statement is constant"); - if (const && cond && top_ls->ls_current->st_notreached) { + register struct lint_stack_entry *lse = find_wdf(); + + dbg_lint_stack("end_loop_stmt"); + ASSERT(lse == top_ls); + if (lse->LS_TEST != TEST_TRUE) + break_merge(lse); + + dbg_lint_stack("end_loop_stmt after break_merge"); + if (!top_ls->LS_LOOP) { /* no break met; this is really an endless loop */ + hwarning("endless %s loop", symbol2str(top_ls->ls_class)); + Free_state(&top_ls->ls_current); } else { - top_ls->ls_current->st_notreached = 0; + Free_state(&top_ls->ls_current); + Free_state(&top_ls->ls_previous->ls_current); + top_ls->ls_previous->ls_current = top_ls->LS_LOOP; } + lint_pop(); } -PRIVATE -cont_break_merge(lse) - struct lint_stack_entry *lse; +end_do_stmt(const, cond) { - /* merge for continue and break statements */ - if (lse->LS_END) { - merge_states(top_ls->ls_current, lse->LS_END, - lse->ls_level, NORMAL); - } - else { - lse->LS_END = copy_state(top_ls->ls_current, lse->ls_level); - } + register struct lint_stack_entry *lse = find_wdf(); + + dbg_lint_stack("end_do_stmt"); + lse->LS_TEST = (!const ? TEST_VAR : cond ? TEST_TRUE : TEST_FALSE); + end_loop_stmt(); + } lint_continue_stmt() { register struct lint_stack_entry *lse = find_wdf(); + dbg_lint_stack("lint_continue_stmt"); if (!lse) return; /* not inside a loop statement */ - cont_break_merge(lse); + cont_merge(lse); top_ls->ls_current->st_notreached = 1; + top_ls->ls_current->st_warned = 0; } +/******** A C T I O N S : S W I T C H ********/ + start_switch_part(expr) struct expr *expr; { @@ -754,22 +843,25 @@ start_switch_part(expr) * following case parts. (Needed for variables declared in a compound * switch-block.) */ - register struct lint_stack_entry *lse = new_lint_stack_entry(); + register struct lint_stack_entry *new = mk_lint_stack_entry(SWITCH); + dbg_lint_stack("start_switch_part"); if (is_cp_cst(expr)) hwarning("value in switch statement is constant"); - lse->ls_class = SWITCH; - lse->ls_current = copy_state(top_ls->ls_current, level); - lse->ls_level = level; - lse->LS_CASE = copy_state(top_ls->ls_current, level); - lse->ls_current->st_notreached = 1; + new->LS_CASE = copy_state(top_ls->ls_current, level); + new->ls_current->st_notreached = 1; + new->ls_current->st_warned = 0; top_ls->ls_current->st_notreached = 1; - lint_push(lse); + top_ls->ls_current->st_warned = 0; + lint_push(new); + lint_expr(expr, USED); /*???*/ } end_switch_stmt() { + + dbg_lint_stack("end_switch_stmt"); if (top_ls->ls_class == CASE) { /* no break after last case or default */ lint_break_stmt(); /* introduce break */ @@ -814,30 +906,33 @@ end_switch_stmt() lint_case_stmt(dflt) { /* A default statement is just a special case statement */ - - register struct lint_stack_entry *lse; register struct lint_stack_entry *cs_entry = find_cs(); + dbg_lint_stack("lint_case_stmt"); if (!cs_entry) return; /* not inside switch */ + if (cs_entry != top_ls) { warning("%s statement in strange context", dflt ? "default" : "case"); return; } - if (cs_entry->ls_class == SWITCH) { + + switch (cs_entry->ls_class) { + register struct lint_stack_entry *new; + + case SWITCH: if (dflt) { cs_entry->LS_DEFAULT_MET = 1; } - lse = new_lint_stack_entry(); - lse->ls_class = CASE; - lse->ls_current = copy_state(top_ls->ls_current, level); - remove_settings(lse->ls_current, level); - lse->ls_level = level; - lint_push(lse); - } - else { - ASSERT(cs_entry->ls_class == CASE); + + new = mk_lint_stack_entry(CASE); + remove_settings(new->ls_current, level); + lint_push(new); + break; + + case CASE: + ASSERT(top_ls->ls_previous->ls_class == SWITCH); if (dflt) { cs_entry->ls_previous->LS_DEFAULT_MET = 1; } @@ -851,6 +946,11 @@ lint_case_stmt(dflt) copy_state(top_ls->ls_previous->ls_current, top_ls->ls_previous->ls_level); remove_settings(top_ls->ls_current, top_ls->ls_level); + break; + + default: + NOTREACHED(); + /*NOTREACHED*/ } } @@ -858,6 +958,7 @@ lint_break_stmt() { register struct lint_stack_entry *lse = find_wdfc(); + dbg_lint_stack("lint_break_stmt"); if (!lse) return; @@ -867,7 +968,7 @@ lint_break_stmt() case DO: /* loop break */ lse->ls_previous->ls_current->st_notreached = 0; - cont_break_merge(lse); + break_merge(lse); break; case CASE: @@ -878,115 +979,145 @@ lint_break_stmt() merge_states(lse->ls_current, lse->ls_previous->ls_current, lse->ls_previous->ls_level, NORMAL); if (lse->ls_previous->LS_BREAK) { - merge_states(top_ls->ls_current, lse->ls_previous->LS_BREAK, - lse->ls_previous->ls_level, NORMAL); + merge_states(top_ls->ls_current, + lse->ls_previous->LS_BREAK, + lse->ls_previous->ls_level, NORMAL); } else { - lse->ls_previous->LS_BREAK = copy_state(top_ls->ls_current, - lse->ls_previous->ls_level); + lse->ls_previous->LS_BREAK = + copy_state(top_ls->ls_current, + lse->ls_previous->ls_level); } if (lse == top_ls) { Free_state(&lse->ls_current); lint_pop(); } break; + default: NOTREACHED(); /*NOTREACHED*/ } top_ls->ls_current->st_notreached = 1; + top_ls->ls_current->st_warned = 0; } +PRIVATE +cont_merge(lse) + struct lint_stack_entry *lse; +{ + /* merge for continue statements */ + if (lse->LS_BODY) { + merge_states(top_ls->ls_current, lse->LS_BODY, + lse->ls_level, NORMAL); + } + else { + lse->LS_BODY = copy_state(top_ls->ls_current, lse->ls_level); + } +} + +PRIVATE +break_merge(lse) + struct lint_stack_entry *lse; +{ + /* merge for break statements */ + if (lse->LS_LOOP) { + merge_states(top_ls->ls_current, lse->LS_LOOP, + lse->ls_level, NORMAL); + } + else { + lse->LS_LOOP = copy_state(top_ls->ls_current, lse->ls_level); + } +} + +/******** A C T I O N S : R E T U R N ********/ + lint_start_function() { - lint_return_stmt(-1); /* initialization */ + + dbg_lint_stack("lint_start_function"); + valreturned = NORETURN; /* initialization */ + return_warned = 0; lint_comment_function(); } lint_end_function() { - extern struct outdef OutDef; - register int fund = func_type->tp_fund; - if ( OutDef.od_valreturned == NOVALRETURNED - && !func_notypegiven - && fund != VOID - ) { - warning("function %s declared %s%s but no value returned", - func_name, - (func_type->tp_unsigned && fund != POINTER) ? - "unsigned " : "", - symbol2str(fund) - ); - } + dbg_lint_stack("lint_end_function"); /* write the function definition record */ outdef(); - /* At this stage it is possible that stack_bottom.ls_current is + /* At this stage it is possible that top_ls->ls_current is * pointing to a state with a list of auto_defs. * These auto_defs must be freed and the state must be filled * with zeros. */ - ASSERT(top_ls == &stack_bottom); - if (top_ls->ls_current->st_auto_list != 0) - free_st_auto_list(top_ls->ls_current->st_auto_list); + ASSERT(!top_ls->ls_previous); + free_auto_list(top_ls->ls_current->st_auto_list); top_ls->ls_current->st_auto_list = 0; top_ls->ls_current->st_notreached = 0; top_ls->ls_current->st_warned = 0; } +lint_implicit_return() +{ + + dbg_lint_stack("lint_implicit_return"); + if (!top_ls->ls_current->st_notreached) { + lint_return_stmt(NOVALRETURNED); + } +} + lint_return_stmt(e) int e; { -/* The statics of this function are initialized by calling it with e = -1. */ - - static int ret_e; - /*-1 no return met yet - * 0 return; met - * 1 return with expression met - */ - static int warned; - - switch (e) { - case -1: - ret_e = -1; - warned = 0; - return; - case 0: - if (top_ls->ls_current->st_notreached) - break; - if (ret_e == 1 && !warned) { - warning("function %s does not always return a value", - func_name); - warned = 1; - } - else - ret_e = 0; - break; - case 1: - if (top_ls->ls_current->st_notreached) - break; - if (ret_e == 0 && !warned) { - warning("function %s does not always return a value", - func_name); - warned = 1; + + dbg_lint_stack("lint_return_stmt"); + if (valreturned == NORETURN) { + /* first return met */ + register int fund = func_type->tp_fund; + + if ( e == NOVALRETURNED + && !func_notypegiven + && fund != VOID + ) { + warning("function %s declared %s%s but no value returned", + func_name, + (func_type->tp_unsigned && fund != POINTER) ? + "unsigned " : "", + symbol2str(fund) + ); + /* adjust */ + e = VALRETURNED; } - else - ret_e = 1; - break; + valreturned = e; + } + else + if (valreturned != e && !return_warned) { + warning("function %s does not always return a value", + func_name); + return_warned = 1; + } + + if (!top_ls->ls_current->st_notreached) { + set_od_valreturned(valreturned); } - if (!top_ls->ls_current->st_notreached) - set_od_valreturned(e); top_ls->ls_current->st_notreached = 1; + top_ls->ls_current->st_warned = 0; } +/******** A C T I O N S : J U M P ********/ + lint_jump_stmt(idf) struct idf *idf; { + + dbg_lint_stack("lint_jump_stmt"); top_ls->ls_current->st_notreached = 1; - if (!idf->id_def) - return; - idf->id_def->df_used = 1; + top_ls->ls_current->st_warned = 0; + if (idf->id_def) + idf->id_def->df_used = 1; } lint_label() @@ -998,6 +1129,7 @@ lint_label() */ register struct auto_def *a = top_ls->ls_current->st_auto_list; + dbg_lint_stack("lint_label"); while (a) { a->ad_maybe_set = 0; a->ad_set = 1; @@ -1005,12 +1137,17 @@ lint_label() } } +/******** A C T I O N S : S T A T E M E N T ********/ + lint_statement() { -/* Check if this statement can be reached - */ +/* Check if this statement can be reached +*/ + + dbg_lint_stack("lint_statement"); if (s_NOTREACHED) { top_ls->ls_current->st_notreached = 1; + top_ls->ls_current->st_warned = 0; s_NOTREACHED = 0; } if (DOT == '{' || DOT == ';') @@ -1030,6 +1167,22 @@ lint_statement() } } +PRIVATE struct lint_stack_entry * +mk_lint_stack_entry(cl) + int cl; +{ +/* Prepare a new stack entry for the lint_stack with class cl. + Copy the top ls_current to this entry and set its level. +*/ + register struct lint_stack_entry *new = new_lint_stack_entry(); + + new->ls_class = cl; + new->ls_current = copy_state(top_ls->ls_current, level); + new->ls_level = level; + + return new; +} + PRIVATE lint_push(lse) struct lint_stack_entry *lse; @@ -1049,64 +1202,59 @@ lint_pop() #ifdef DEBUG /* FOR DEBUGGING */ -print_lint_stack() +PRIVATE +pr_lint_state(nm, st) + char *nm; + struct state *st; +{ + print("%s: ", nm); + if (st) { + print("notreached == %d ", st->st_notreached); + print_autos(st->st_auto_list); + } + else { + print("NULL"); + } + print("\n"); +} + +print_lint_stack(msg) + char *msg; { register struct lint_stack_entry *lse = top_ls; + print("Lint stack: %s(level=%d)\n", msg, level); while (lse) { print(" |-------------- level %d ------------\n", lse->ls_level); - print(" |cur: "); - if (lse->ls_current) { - print_autos(lse->ls_current->st_auto_list); - print(" |st_notreached == %d\n", - lse->ls_current->st_notreached); - } - else - print("\n"); + pr_lint_state(" |cur", lse->ls_current); + print(" |class == %s\n", lse->ls_class ? symbol2str(lse->ls_class) : "{"); + switch (lse->ls_class) { case SWITCH: - print(" |LS_BREAK: "); - if (lse->LS_BREAK) { - print_autos(lse->LS_BREAK->st_auto_list); - print(" |st_notreached == %d\n", - lse->LS_BREAK->st_notreached); - } - else - print("\n"); - print(" |LS_CASE: "); - if (lse->LS_CASE) { - print_autos(lse->LS_CASE->st_auto_list); - print(" |st_notreached == %d\n", - lse->LS_CASE->st_notreached); - } - else - print("\n"); + pr_lint_state(" |LS_BREAK", lse->LS_BREAK); + pr_lint_state(" |LS_CASE", lse->LS_CASE); break; + case DO: case WHILE: case FOR: - print(" |LS_END: "); - if (lse->LS_END) { - print_autos(lse->LS_END->st_auto_list); - print(" |st_notreached == %d\n", - lse->LS_END->st_notreached); - } - else - print("\n"); + print(" |LS_TEST == %s\n", + lse->LS_TEST == TEST_VAR ? "TEST_VAR" : + lse->LS_TEST == TEST_TRUE ? "TEST_TRUE" : + lse->LS_TEST == TEST_FALSE ? "TEST_FALSE" : + "<>" + ); + pr_lint_state(" |LS_BODY", lse->LS_BODY); + pr_lint_state(" |LS_LOOP", lse->LS_LOOP); break; + case IF: - print(" |LS_IF_STATE: "); - if (lse->LS_IF_STATE) { - print_autos(lse->LS_IF_STATE->st_auto_list); - print(" |st_notreached == %d\n", - lse->LS_IF_STATE->st_notreached); - } - else - print("\n"); + pr_lint_state(" |LS_IF", lse->LS_IF); break; + default: break; } @@ -1120,11 +1268,10 @@ print_autos(a) { while (a) { print("%s", a->ad_idf->id_text); - print("(l=%d)", a->ad_def->df_level); + print("(lvl=%d)", a->ad_def->df_level); print("(U%dS%dM%d) ", a->ad_used, a->ad_set, a->ad_maybe_set); a = a->next; } - print("\n"); } #endif DEBUG diff --git a/lang/cem/cemcom/program.g b/lang/cem/cemcom/program.g index 64a1158cc..7e2d00a78 100644 --- a/lang/cem/cemcom/program.g +++ b/lang/cem/cemcom/program.g @@ -58,7 +58,7 @@ #include "expr.h" #include "def.h" #ifdef LINT -#include "l_state.h" +#include "l_lint.h" #endif LINT #ifndef NOPP @@ -205,11 +205,11 @@ function(struct decspecs *ds; struct declarator *dc;) { end_proc(fbytes); #ifdef LINT - lint_return_stmt(0); /* implicit return at end of function */ + lint_implicit_return(); #endif LINT unstack_level(); /* L_FORMAL2 declarations */ #ifdef LINT - check_args_used(); + lint_end_formals(); #endif LINT unstack_level(); /* L_FORMAL1 declarations */ #ifdef LINT diff --git a/lang/cem/cemcom/stack.c b/lang/cem/cemcom/stack.c index 3be2dece2..27724ecda 100644 --- a/lang/cem/cemcom/stack.c +++ b/lang/cem/cemcom/stack.c @@ -101,7 +101,7 @@ unstack_level() #endif DEBUG #ifdef LINT - lint_local_level(local_level); + lint_end_local(local_level); #endif LINT /* The implementation below is more careful than strictly @@ -177,7 +177,7 @@ unstack_world() register struct stack_entry *se = local_level->sl_entry; #ifdef LINT - lint_global_level(local_level); + lint_end_global(local_level); #endif LINT open_name_list(); diff --git a/lang/cem/cemcom/statement.g b/lang/cem/cemcom/statement.g index 53b0aeba2..b8c2cfb99 100644 --- a/lang/cem/cemcom/statement.g +++ b/lang/cem/cemcom/statement.g @@ -23,13 +23,12 @@ #include "def.h" #ifdef LINT #include "l_lint.h" -#include "l_state.h" #endif LINT extern int level; } -/* Each statement construction is stacked in order to trace a +/* Each statement construction is stacked in order to trace a ??? statement to such a construction. Example: a case statement should be recognized as a piece of the most enclosing switch statement. */ @@ -209,18 +208,16 @@ while_statement if (expr->VL_VALUE == (arith)0) { C_bra(l_break); } -#ifdef LINT - start_loop_stmt(WHILE, 1, - expr->VL_VALUE != (arith)0); -#endif LINT } else { code_expr(expr, RVAL, TRUE, l_body, l_break); C_df_ilb(l_body); + } + #ifdef LINT - start_loop_stmt(WHILE, 0, 0); + start_while_stmt(expr); #endif LINT - } + } ')' statement @@ -230,6 +227,7 @@ while_statement unstack_stmt(); free_expression(expr); #ifdef LINT + end_loop_body(); end_loop_stmt(); #endif LINT } @@ -246,13 +244,17 @@ do_statement { C_df_ilb(l_body); stack_stmt(l_break, l_continue); #ifdef LINT - start_loop_stmt(DO, 1, 1); + start_do_stmt(); #endif LINT } statement WHILE '(' - { C_df_ilb(l_continue); + { +#ifdef LINT + end_loop_body(); +#endif LINT + C_df_ilb(l_continue); } expression(&expr) { @@ -287,9 +289,6 @@ for_statement label l_continue = text_label(); label l_body = text_label(); label l_test = text_label(); -#ifdef LINT - int const = 1, cond = 1; /* the default case */ -#endif LINT } : FOR @@ -312,17 +311,10 @@ for_statement if (e_test->VL_VALUE == (arith)0) { C_bra(l_break); } -#ifdef LINT - const = 1, - cond = e_test->VL_VALUE != (arith)0; -#endif LINT } else { code_expr(e_test, RVAL, TRUE, l_body, l_break); C_df_ilb(l_body); -#ifdef LINT - const = 0, cond = 0; -#endif LINT } } ]? @@ -331,13 +323,13 @@ for_statement ')' { #ifdef LINT - start_loop_stmt(FOR, const, cond); + start_for_stmt(e_test); #endif LINT } statement { #ifdef LINT - end_loop_stmt(); + end_loop_body(); #endif LINT C_df_ilb(l_continue); if (e_incr) @@ -349,6 +341,9 @@ for_statement free_expression(e_init); free_expression(e_test); free_expression(e_incr); +#ifdef LINT + end_loop_stmt(); +#endif LINT } ; @@ -423,7 +418,7 @@ return_statement do_return_expr(expr); free_expression(expr); #ifdef LINT - lint_return_stmt(1); + lint_return_stmt(VALRETURNED); #endif LINT } | @@ -431,7 +426,7 @@ return_statement { do_return(); #ifdef LINT - lint_return_stmt(0); + lint_return_stmt(NOVALRETURNED); #endif LINT } ]