1308 lines
		
	
	
	
		
			27 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1308 lines
		
	
	
	
		
			27 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
 | 
						|
 * See the copyright notice in the ACK home directory, in the file "Copyright".
 | 
						|
 */
 | 
						|
/* $Id$ */
 | 
						|
/*	Lint status checking	*/
 | 
						|
 | 
						|
#include	"lint.h"
 | 
						|
 | 
						|
#ifdef	LINT
 | 
						|
 | 
						|
#include	<alloc.h>	/* for st_free */
 | 
						|
#include	"interface.h"
 | 
						|
#include	"assert.h"
 | 
						|
#include	"debug.h"
 | 
						|
#ifdef ANSI
 | 
						|
#include	<flt_arith.h>
 | 
						|
#endif /* ANSI */
 | 
						|
#include	"arith.h"
 | 
						|
#include	"label.h"
 | 
						|
#include	"expr.h"
 | 
						|
#include	"idf.h"
 | 
						|
#include	"def.h"
 | 
						|
#include	"code.h"	/* RVAL etc */
 | 
						|
#include	"LLlex.h"
 | 
						|
#include	"Lpars.h"
 | 
						|
#include	"stack.h"
 | 
						|
#include	"type.h"
 | 
						|
#include	"level.h"
 | 
						|
#include	"l_lint.h"
 | 
						|
#include	"l_brace.h"
 | 
						|
#include	"l_state.h"
 | 
						|
#include	"l_comment.h"
 | 
						|
#include	"l_outdef.h"
 | 
						|
 | 
						|
#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 *top_ls;
 | 
						|
 | 
						|
/* global variables for the brace stack */
 | 
						|
PRIVATE int brace_count;
 | 
						|
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_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_merge();
 | 
						|
PRIVATE break_merge();
 | 
						|
PRIVATE struct lint_stack_entry *mk_lint_stack_entry();
 | 
						|
PRIVATE lint_push();
 | 
						|
PRIVATE lint_pop();
 | 
						|
 | 
						|
lint_init_stack()
 | 
						|
{
 | 
						|
/*	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;
 | 
						|
	br->next = top_br;
 | 
						|
	top_br = br;
 | 
						|
}	
 | 
						|
 | 
						|
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();
 | 
						|
	}
 | 
						|
 | 
						|
	check_autos();
 | 
						|
	end_brace(stl);
 | 
						|
}
 | 
						|
 | 
						|
PRIVATE
 | 
						|
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;
 | 
						|
 | 
						|
	while (se) {
 | 
						|
		register struct idf *idf = se->se_idf;
 | 
						|
		register struct def *def = idf->id_def;
 | 
						|
 | 
						|
		if (def) {
 | 
						|
			lint_1_local(idf, def);
 | 
						|
		}
 | 
						|
		se = se->next;
 | 
						|
	}
 | 
						|
 | 
						|
	/* remove entry from brace stack */
 | 
						|
	br = top_br;
 | 
						|
	top_br = br->next;
 | 
						|
	free_brace(br);
 | 
						|
}
 | 
						|
 | 
						|
PRIVATE
 | 
						|
lint_1_local(idf, def)
 | 
						|
	struct idf *idf;
 | 
						|
	struct def *def;
 | 
						|
{
 | 
						|
	register int sc = def->df_sc;
 | 
						|
 | 
						|
	if (	(sc == STATIC || sc == LABEL)
 | 
						|
	&&	!def->df_used
 | 
						|
	&&	!is_anon_idf(idf)
 | 
						|
	) {
 | 
						|
		def_warning(def, "%s %s not applied anywhere in function %s",
 | 
						|
			symbol2str(sc), idf->id_text, func_name);
 | 
						|
	}
 | 
						|
 | 
						|
	if (	loptions['h']
 | 
						|
	&&	sc == AUTO
 | 
						|
	&&	!def->df_initialized
 | 
						|
	&&	def->df_firstbrace != 0
 | 
						|
	&&	def->df_minlevel != level
 | 
						|
	&&	!is_anon_idf(idf)
 | 
						|
	) {
 | 
						|
		register int diff = def->df_minlevel - level;
 | 
						|
 | 
						|
		def_warning(def,
 | 
						|
			"local %s could be declared %d level%s deeper",
 | 
						|
			idf->id_text, diff, (diff == 1 ? "" : "s")
 | 
						|
		);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
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;
 | 
						|
		register struct def *def = idf->id_def;
 | 
						|
 | 
						|
		if (def) {
 | 
						|
			lint_1_global(idf, def);
 | 
						|
		}
 | 
						|
		se = se->next;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
PRIVATE
 | 
						|
lint_1_global(idf, def)
 | 
						|
	struct idf *idf;
 | 
						|
	struct def *def;
 | 
						|
{
 | 
						|
	register int sc = def->df_sc;
 | 
						|
	register int fund = def->df_type->tp_fund;
 | 
						|
 | 
						|
	switch (sc) {
 | 
						|
	case STATIC:
 | 
						|
	case EXTERN:
 | 
						|
	case GLOBAL:
 | 
						|
#ifdef	IMPLICIT
 | 
						|
	case IMPLICIT:
 | 
						|
#endif	/* IMPLICIT */
 | 
						|
		if (fund == ERRONEOUS)
 | 
						|
			break;
 | 
						|
 | 
						|
		if (def->df_set || def->df_used) {
 | 
						|
			/* Output a line to the intermediate file for
 | 
						|
			 * used external variables (including functions)
 | 
						|
			 */
 | 
						|
			output_use(idf);
 | 
						|
		}
 | 
						|
 | 
						|
		if (sc == STATIC && !def->df_used) {
 | 
						|
			if (def->df_set) {
 | 
						|
				if (!is_anon_idf(idf) && fund != ERRONEOUS) {
 | 
						|
					def_warning(def,
 | 
						|
						"%s %s %s set but not used",
 | 
						|
						symbol2str(sc),
 | 
						|
						symbol2str(fund),
 | 
						|
						idf->id_text);
 | 
						|
				}
 | 
						|
			}
 | 
						|
			else {
 | 
						|
				if (!is_anon_idf(idf) && fund != ERRONEOUS) {
 | 
						|
					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
 | 
						|
			&&	!is_anon_idf(idf)
 | 
						|
			&&	fund != ERRONEOUS
 | 
						|
			) {
 | 
						|
				def_warning(def,
 | 
						|
					"%s %s %s not used anywhere",
 | 
						|
					symbol2str(sc),
 | 
						|
					symbol2str(fund),
 | 
						|
					idf->id_text);
 | 
						|
			}
 | 
						|
		}
 | 
						|
		break;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
change_state(idf, to_state)
 | 
						|
	struct idf *idf;
 | 
						|
	int to_state;			/* SET or USED */
 | 
						|
{
 | 
						|
/* Changes the state of the variable identified by idf in the current state
 | 
						|
 * on top of the stack.
 | 
						|
 * 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;
 | 
						|
 | 
						|
	ASSERT(def);
 | 
						|
 | 
						|
	switch (to_state) {
 | 
						|
	case SET:
 | 
						|
		def->df_set = 1;
 | 
						|
		break;
 | 
						|
	case USED:
 | 
						|
		def->df_used = 1;
 | 
						|
		break;
 | 
						|
	}
 | 
						|
 | 
						|
	/* 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, global definition */
 | 
						|
		return;
 | 
						|
 | 
						|
	switch (to_state) {
 | 
						|
	case SET:
 | 
						|
		a->ad_maybe_set = 0;
 | 
						|
		a->ad_set = 1;
 | 
						|
		break;
 | 
						|
	case USED:
 | 
						|
		if (!a->ad_set) {
 | 
						|
			if (!is_anon_idf(idf)) {
 | 
						|
				warning("variable %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;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
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 formal parameters.
 | 
						|
 */
 | 
						|
	register struct def *def = idf->id_def;
 | 
						|
 | 
						|
	ASSERT(def);
 | 
						|
 | 
						|
	switch (def->df_sc) {
 | 
						|
		register struct auto_def *a;
 | 
						|
	case AUTO:
 | 
						|
	case REGISTER:
 | 
						|
		if (def->df_level < L_LOCAL)
 | 
						|
			return;		/* a formal */
 | 
						|
 | 
						|
		a = new_auto_def();
 | 
						|
 | 
						|
		a->ad_idf = idf;
 | 
						|
		a->ad_def = 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;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
PRIVATE
 | 
						|
check_autos()
 | 
						|
{
 | 
						|
/* 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 *a = top_ls->ls_current->st_auto_list;
 | 
						|
 | 
						|
	ASSERT(!(a && a->ad_def->df_level > level));
 | 
						|
	while (a && a->ad_def->df_level == level) {
 | 
						|
		struct idf *idf = a->ad_idf;
 | 
						|
		struct def *def = idf->id_def;
 | 
						|
 | 
						|
		if (!def->df_used && !is_anon_idf(idf)) {
 | 
						|
			if (def->df_set || a->ad_maybe_set) {
 | 
						|
				def_warning(def,
 | 
						|
					"%s set but not used in function %s",
 | 
						|
					idf->id_text, func_name);
 | 
						|
			}
 | 
						|
			else {
 | 
						|
				def_warning(def,
 | 
						|
					"%s not used anywhere in function %s",
 | 
						|
					idf->id_text, func_name);
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		{	/* free a */
 | 
						|
			register struct auto_def *aux = a;
 | 
						|
			a = a->next;
 | 
						|
			free_auto_def(aux);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	top_ls->ls_current->st_auto_list = a;
 | 
						|
}
 | 
						|
 | 
						|
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;
 | 
						|
 | 
						|
		if (	(def && !def->df_used)
 | 
						|
		&&	!(f_ARGSUSED || LINTLIB)
 | 
						|
		&&	!is_anon_idf(se->se_idf)
 | 
						|
		) {
 | 
						|
			def_warning(def, "argument %s not used in function %s",
 | 
						|
					se->se_idf->id_text, func_name);
 | 
						|
		}
 | 
						|
		se = se->next;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
PRIVATE struct auto_def *
 | 
						|
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();
 | 
						|
 | 
						|
		*hook = a;
 | 
						|
		*a = *from_al;
 | 
						|
		hook = &a->next;
 | 
						|
		from_al = from_al->next;
 | 
						|
	}
 | 
						|
 | 
						|
	return start;
 | 
						|
}
 | 
						|
 | 
						|
PRIVATE
 | 
						|
free_auto_list(a)
 | 
						|
	register struct 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_auto_list(from_st->st_auto_list, lvl);
 | 
						|
	st->st_notreached = from_st->st_notreached;
 | 
						|
	st->st_warned = from_st->st_warned;
 | 
						|
	return st;
 | 
						|
}
 | 
						|
 | 
						|
PRIVATE
 | 
						|
Free_state(stp)
 | 
						|
	struct state **stp;
 | 
						|
{
 | 
						|
/* This function also frees the list of auto_defs
 | 
						|
 */
 | 
						|
	free_auto_list((*stp)->st_auto_list);
 | 
						|
	free_state(*stp);
 | 
						|
	*stp = 0;
 | 
						|
}
 | 
						|
 | 
						|
PRIVATE
 | 
						|
remove_settings(st, lvl)
 | 
						|
	struct state *st;
 | 
						|
	int lvl;
 | 
						|
{
 | 
						|
/* 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 = st->st_auto_list;
 | 
						|
 | 
						|
	while (a && a->ad_def->df_level == lvl) {
 | 
						|
		a->ad_set = a->ad_maybe_set = 0;
 | 
						|
		a = a->next;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/******** M E R G E ********/
 | 
						|
 | 
						|
/* modes for merging */
 | 
						|
#define	NORMAL		0
 | 
						|
#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.
 | 
						|
 * a1 is left unchanged.
 | 
						|
 * a2 is used to create this result.
 | 
						|
 * The fields are set as follows:
 | 
						|
 *	a1_set + a2_set		-> set
 | 
						|
 *		+ a?_maybe_set	-> maybe set
 | 
						|
 *		ELSE		-> NOT set && NOT maybe set
 | 
						|
 *	*	+ a?_used	-> used
 | 
						|
 *
 | 
						|
 * For mode == CASE_BREAK:
 | 
						|
 * First a2 is taken as the result, then
 | 
						|
 * variables NOT set in a2 and set or maybe set in a1 become 'maybe set'
 | 
						|
 *
 | 
						|
 * For mode == USE_ONLY:
 | 
						|
 * Start with a2 as the result.
 | 
						|
 * Variables used in a1 become used in a2.
 | 
						|
 * The rest of the result is not changed.
 | 
						|
 */
 | 
						|
	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) {
 | 
						|
		register struct auto_def *aux = a2;
 | 
						|
		a2 = a2->next;
 | 
						|
		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;
 | 
						|
 | 
						|
		if (mode != USE_ONLY) {
 | 
						|
			if (	(	!a2->ad_set
 | 
						|
				&&	(a1->ad_set || a1->ad_maybe_set)
 | 
						|
				)
 | 
						|
			||	(	mode == NORMAL
 | 
						|
				&&	!a1->ad_set
 | 
						|
				&&	(a2->ad_set || a2->ad_maybe_set)
 | 
						|
				)
 | 
						|
			) {
 | 
						|
				a2->ad_set = 0;
 | 
						|
				a2->ad_maybe_set = 1;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		a1 = a1->next;
 | 
						|
		a2 = a2->next;
 | 
						|
	}
 | 
						|
	ASSERT(!a2);
 | 
						|
	return a;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/******** L I N T   S T A C K   S E A R C H I N G ********/
 | 
						|
 | 
						|
/* The next four find-functions search the lint_stack for an entry.
 | 
						|
 * The letters mean : w: WHILE; d: DO; f: FOR; s: SWITCH; c: CASE.
 | 
						|
 */
 | 
						|
 | 
						|
PRIVATE struct lint_stack_entry *
 | 
						|
find_wdf()
 | 
						|
{
 | 
						|
	register struct lint_stack_entry *lse = top_ls;
 | 
						|
 | 
						|
	while (lse) {
 | 
						|
		switch (lse->ls_class) {
 | 
						|
		case WHILE:
 | 
						|
		case DO:
 | 
						|
		case FOR:
 | 
						|
			return lse;
 | 
						|
		}
 | 
						|
		lse = lse->ls_previous;
 | 
						|
	}
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
PRIVATE struct lint_stack_entry *
 | 
						|
find_wdfc()
 | 
						|
{
 | 
						|
	register struct lint_stack_entry *lse = top_ls;
 | 
						|
 | 
						|
	while (lse) {
 | 
						|
		switch (lse->ls_class) {
 | 
						|
		case WHILE:
 | 
						|
		case DO:
 | 
						|
		case FOR:
 | 
						|
		case CASE:
 | 
						|
			return lse;
 | 
						|
		}
 | 
						|
		lse = lse->ls_previous;
 | 
						|
	}
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
PRIVATE struct lint_stack_entry *
 | 
						|
find_cs()
 | 
						|
{
 | 
						|
	register struct lint_stack_entry *lse = top_ls;
 | 
						|
 | 
						|
	while (lse) {
 | 
						|
		switch (lse->ls_class) {
 | 
						|
		case CASE:
 | 
						|
		case SWITCH:
 | 
						|
			return lse;
 | 
						|
		}
 | 
						|
		lse = lse->ls_previous;
 | 
						|
	}
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
/******** A C T I O N S : I F ********/
 | 
						|
 | 
						|
start_if_part(cst)
 | 
						|
{
 | 
						|
	register struct lint_stack_entry *new = mk_lint_stack_entry(IF);
 | 
						|
 | 
						|
	dbg_lint_stack("start_if_part");
 | 
						|
	if (cst)
 | 
						|
		hwarning("condition in if statement is constant");
 | 
						|
 | 
						|
	lint_push(new);
 | 
						|
/*	ls_current:	the state at the start of the if-part
 | 
						|
*/
 | 
						|
}
 | 
						|
 | 
						|
start_else_part()
 | 
						|
{
 | 
						|
/*	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 = 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_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()
 | 
						|
{
 | 
						|
/*	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);
 | 
						|
	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.
 | 
						|
	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, cst, cond)
 | 
						|
{
 | 
						|
/*	If cst, the condition is a constant and its value is cond
 | 
						|
*/
 | 
						|
	register struct lint_stack_entry *new = mk_lint_stack_entry(looptype);
 | 
						|
 | 
						|
	dbg_lint_stack("start_loop_stmt");
 | 
						|
	if (cst && !cond) {
 | 
						|
		/* while (0) | for (;0;) */
 | 
						|
		hwarning("condition in %s statement is always false",
 | 
						|
						symbol2str(looptype));
 | 
						|
		new->ls_current->st_notreached = 1;
 | 
						|
	}
 | 
						|
	if (cst && cond) {
 | 
						|
		/* while (1) | for (;;) | do */
 | 
						|
		/*	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 {
 | 
						|
		new->LS_LOOP = copy_state(top_ls->ls_current, level);
 | 
						|
	}
 | 
						|
	new->LS_TEST = (!cst ? 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_body()
 | 
						|
{
 | 
						|
	register struct lint_stack_entry *lse = find_wdf();
 | 
						|
 | 
						|
	dbg_lint_stack("end_loop_body");
 | 
						|
	ASSERT(lse == top_ls);
 | 
						|
	if (!lse->ls_current->st_notreached)
 | 
						|
		cont_merge(lse);
 | 
						|
}
 | 
						|
 | 
						|
end_loop_stmt()
 | 
						|
{
 | 
						|
	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 {
 | 
						|
		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();
 | 
						|
}
 | 
						|
 | 
						|
end_do_stmt(cst, cond)
 | 
						|
{
 | 
						|
	register struct lint_stack_entry *lse = find_wdf();
 | 
						|
 | 
						|
	dbg_lint_stack("end_do_stmt");
 | 
						|
	if (cst && !cond) {
 | 
						|
		/* do ... while (0) */
 | 
						|
		hwarning("condition in do statement is always false");
 | 
						|
	}
 | 
						|
	lse->LS_TEST = (!cst ? 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_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(cst)
 | 
						|
{
 | 
						|
/* ls_current of a SWITCH entry has different meaning from ls_current of
 | 
						|
 * other entries. It keeps track of which variables are used in all
 | 
						|
 * following case parts. (Needed for variables declared in a compound
 | 
						|
 * switch-block.)
 | 
						|
 */
 | 
						|
	register struct lint_stack_entry *new = mk_lint_stack_entry(SWITCH);
 | 
						|
 | 
						|
	dbg_lint_stack("start_switch_part");
 | 
						|
	if (cst)
 | 
						|
		hwarning("value in switch statement is constant");
 | 
						|
 | 
						|
	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;
 | 
						|
	top_ls->ls_current->st_warned = 0;
 | 
						|
	lint_push(new);
 | 
						|
}
 | 
						|
 | 
						|
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 */
 | 
						|
	}
 | 
						|
 | 
						|
	if (!top_ls->LS_DEFAULT_MET) {
 | 
						|
		top_ls->ls_current->st_notreached = 0;
 | 
						|
		if (top_ls->LS_BREAK) {
 | 
						|
			merge_states(top_ls->ls_current, top_ls->LS_BREAK,
 | 
						|
						top_ls->ls_level, NORMAL);
 | 
						|
			Free_state(&top_ls->ls_current);
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			top_ls->LS_BREAK = top_ls->ls_current;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		Free_state(&top_ls->ls_current);
 | 
						|
	}
 | 
						|
 | 
						|
	if (top_ls->LS_BREAK) {
 | 
						|
		merge_states(top_ls->LS_CASE, top_ls->LS_BREAK,
 | 
						|
						top_ls->ls_level, CASE_BREAK);
 | 
						|
		Free_state(&top_ls->LS_CASE);
 | 
						|
	}
 | 
						|
	else {
 | 
						|
		top_ls->LS_BREAK = top_ls->LS_CASE;
 | 
						|
	}
 | 
						|
 | 
						|
	top_ls->LS_BREAK->st_notreached =
 | 
						|
			top_ls->ls_previous->ls_current->st_notreached;
 | 
						|
				/* yack */
 | 
						|
	Free_state(&top_ls->ls_previous->ls_current);
 | 
						|
 | 
						|
	if (!top_ls->LS_DEFAULT_MET)
 | 
						|
		top_ls->LS_BREAK->st_notreached = 0;
 | 
						|
	top_ls->ls_previous->ls_current = top_ls->LS_BREAK;
 | 
						|
 | 
						|
	lint_pop();
 | 
						|
}
 | 
						|
 | 
						|
lint_case_stmt(dflt)
 | 
						|
{
 | 
						|
/* A default statement is just a special case statement */
 | 
						|
	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;
 | 
						|
	}
 | 
						|
 | 
						|
	switch (cs_entry->ls_class) {
 | 
						|
		register struct lint_stack_entry *new;
 | 
						|
 | 
						|
	case SWITCH:
 | 
						|
		if (dflt) {
 | 
						|
			cs_entry->LS_DEFAULT_MET = 1;
 | 
						|
		}
 | 
						|
 | 
						|
		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;
 | 
						|
		}
 | 
						|
		merge_states(top_ls->ls_current, top_ls->ls_previous->LS_CASE,
 | 
						|
				top_ls->ls_previous->ls_level, NORMAL);
 | 
						|
		merge_states(top_ls->ls_current,
 | 
						|
				top_ls->ls_previous->ls_current,
 | 
						|
				top_ls->ls_previous->ls_level, NORMAL);
 | 
						|
		Free_state(&top_ls->ls_current);
 | 
						|
		top_ls->ls_current =
 | 
						|
			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*/
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
lint_break_stmt()
 | 
						|
{
 | 
						|
	register struct lint_stack_entry *lse = find_wdfc();
 | 
						|
 | 
						|
	dbg_lint_stack("lint_break_stmt");
 | 
						|
	if (!lse)
 | 
						|
		return;
 | 
						|
 | 
						|
	switch (lse->ls_class) {
 | 
						|
	case WHILE:
 | 
						|
	case FOR:
 | 
						|
	case DO:
 | 
						|
		/* loop break */
 | 
						|
		lse->ls_previous->ls_current->st_notreached = 0;
 | 
						|
		break_merge(lse);
 | 
						|
		break;
 | 
						|
 | 
						|
	case CASE:
 | 
						|
		/* case break */
 | 
						|
		if (!top_ls->ls_current->st_notreached) {
 | 
						|
			lse->ls_previous->ls_previous->ls_current->st_notreached = 0;
 | 
						|
		}
 | 
						|
		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);
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			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()
 | 
						|
{
 | 
						|
 | 
						|
	dbg_lint_stack("lint_start_function");
 | 
						|
	valreturned = NORETURN;		/* initialization */
 | 
						|
	return_warned = 0;
 | 
						|
	lint_comment_function();
 | 
						|
}
 | 
						|
 | 
						|
lint_end_function()
 | 
						|
{
 | 
						|
 | 
						|
	dbg_lint_stack("lint_end_function");
 | 
						|
	/* write the function definition record */
 | 
						|
	outdef();
 | 
						|
 | 
						|
	/* 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->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;
 | 
						|
{
 | 
						|
 | 
						|
	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
 | 
						|
		&&	fund != ERRONEOUS
 | 
						|
		) {
 | 
						|
			warning("function %s declared %s%s but no value returned",
 | 
						|
				func_name,
 | 
						|
				(func_type->tp_unsigned && fund != POINTER) ?
 | 
						|
					"unsigned " : "",
 | 
						|
				 symbol2str(fund)
 | 
						|
			);
 | 
						|
			/* adjust */
 | 
						|
			e = VALRETURNED;
 | 
						|
		}
 | 
						|
		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);
 | 
						|
	}
 | 
						|
	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;
 | 
						|
	top_ls->ls_current->st_warned = 0;
 | 
						|
	if (idf->id_def)
 | 
						|
		idf->id_def->df_used = 1;
 | 
						|
}
 | 
						|
 | 
						|
lint_label()
 | 
						|
{
 | 
						|
/*	When meeting a label, we should take the intersection of all
 | 
						|
	settings at all goto's leading this way, but this cannot reasonably
 | 
						|
	be done.  So we assume that the user knows what he is doing and set
 | 
						|
	all automatic variables to set.
 | 
						|
*/
 | 
						|
	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;
 | 
						|
		a = a->next;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/******** 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
 | 
						|
*/
 | 
						|
 | 
						|
	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 == ';')
 | 
						|
		return;
 | 
						|
	if (top_ls->ls_current->st_warned)
 | 
						|
		return;
 | 
						|
	if (top_ls->ls_current->st_notreached) {
 | 
						|
		if (DOT != CASE && DOT != DEFAULT && AHEAD != ':') {
 | 
						|
			if (DOT != BREAK || loptions['b'])
 | 
						|
				warning("statement cannot be reached");
 | 
						|
			top_ls->ls_current->st_warned = 1;
 | 
						|
		}
 | 
						|
		else {
 | 
						|
			top_ls->ls_current->st_notreached = 0;
 | 
						|
			top_ls->ls_current->st_warned = 0;
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
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;
 | 
						|
{
 | 
						|
	lse->ls_previous = top_ls;
 | 
						|
	top_ls->next = lse;
 | 
						|
	top_ls = lse;
 | 
						|
}
 | 
						|
 | 
						|
PRIVATE
 | 
						|
lint_pop()
 | 
						|
{
 | 
						|
	top_ls = top_ls->ls_previous;
 | 
						|
	free_lint_stack_entry(top_ls->next);
 | 
						|
}
 | 
						|
 | 
						|
#ifdef	DEBUG
 | 
						|
/* FOR DEBUGGING */
 | 
						|
 | 
						|
PRIVATE
 | 
						|
print_autos(a)
 | 
						|
	struct auto_def *a;
 | 
						|
{
 | 
						|
	while (a) {
 | 
						|
		struct idf *idf = a->ad_idf;
 | 
						|
		struct def *def = idf->id_def;
 | 
						|
 | 
						|
		print("%s", idf->id_text);
 | 
						|
		print("(lvl=%d)", a->ad_def->df_level);
 | 
						|
		print("(u%ds%dm%d U%dS%d) ",
 | 
						|
			a->ad_used, a->ad_set, a->ad_maybe_set,
 | 
						|
			def->df_used, def->df_set
 | 
						|
		);
 | 
						|
		a = a->next;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
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);
 | 
						|
		pr_lint_state("  |current", lse->ls_current);
 | 
						|
 | 
						|
		print("  |class == %s\n",
 | 
						|
			lse->ls_class ? symbol2str(lse->ls_class) : "{");
 | 
						|
 | 
						|
		switch (lse->ls_class) {
 | 
						|
		case SWITCH:
 | 
						|
			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_TEST == %s\n",
 | 
						|
				lse->LS_TEST == TEST_VAR ? "TEST_VAR" :
 | 
						|
				lse->LS_TEST == TEST_TRUE ? "TEST_TRUE" :
 | 
						|
				lse->LS_TEST == TEST_FALSE ? "TEST_FALSE" :
 | 
						|
				"<<BAD VALUE>>"
 | 
						|
			);
 | 
						|
			pr_lint_state("   |LS_BODY", lse->LS_BODY);
 | 
						|
			pr_lint_state("   |LS_LOOP", lse->LS_LOOP);
 | 
						|
			break;
 | 
						|
 | 
						|
		case IF:
 | 
						|
			pr_lint_state("   |LS_IF", lse->LS_IF);
 | 
						|
			break;
 | 
						|
 | 
						|
		default:
 | 
						|
			break;
 | 
						|
		}
 | 
						|
		lse = lse->ls_previous;
 | 
						|
	}
 | 
						|
	print("  |--------------\n\n");
 | 
						|
}
 | 
						|
 | 
						|
#endif	/* DEBUG */
 | 
						|
 | 
						|
#endif	/* LINT */
 |