chk.c revision 91586
191586Smarkm/* $NetBSD: chk.c,v 1.15 2002/01/21 19:49:52 tv Exp $ */
212099Sjoerg
312099Sjoerg/*
491586Smarkm * Copyright (c) 1996 Christopher G. Demetriou.  All Rights Reserved.
512099Sjoerg * Copyright (c) 1994, 1995 Jochen Pohl
612099Sjoerg * All Rights Reserved.
712099Sjoerg *
812099Sjoerg * Redistribution and use in source and binary forms, with or without
912099Sjoerg * modification, are permitted provided that the following conditions
1012099Sjoerg * are met:
1112099Sjoerg * 1. Redistributions of source code must retain the above copyright
1212099Sjoerg *    notice, this list of conditions and the following disclaimer.
1312099Sjoerg * 2. Redistributions in binary form must reproduce the above copyright
1412099Sjoerg *    notice, this list of conditions and the following disclaimer in the
1512099Sjoerg *    documentation and/or other materials provided with the distribution.
1612099Sjoerg * 3. All advertising materials mentioning features or use of this software
1712099Sjoerg *    must display the following acknowledgement:
1812099Sjoerg *      This product includes software developed by Jochen Pohl for
1912099Sjoerg *	The NetBSD Project.
2012099Sjoerg * 4. The name of the author may not be used to endorse or promote products
2112099Sjoerg *    derived from this software without specific prior written permission.
2212099Sjoerg *
2312099Sjoerg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2412099Sjoerg * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2512099Sjoerg * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2612099Sjoerg * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2712099Sjoerg * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2812099Sjoerg * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2912099Sjoerg * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3012099Sjoerg * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3112099Sjoerg * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3212099Sjoerg * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3312099Sjoerg */
3412099Sjoerg
3591586Smarkm#include <sys/cdefs.h>
3691586Smarkm#if defined(__RCSID) && !defined(lint)
3791586Smarkm__RCSID("$NetBSD: chk.c,v 1.15 2002/01/21 19:49:52 tv Exp $");
3812099Sjoerg#endif
3912099Sjoerg
4012099Sjoerg#include <ctype.h>
4112099Sjoerg#include <limits.h>
4291586Smarkm#include <stdlib.h>
4312099Sjoerg
4412099Sjoerg#include "lint2.h"
4512099Sjoerg
4691586Smarkmstatic	void	chkund(hte_t *);
4791586Smarkmstatic	void	chkdnu(hte_t *);
4891586Smarkmstatic	void	chkdnud(hte_t *);
4991586Smarkmstatic	void	chkmd(hte_t *);
5091586Smarkmstatic	void	chkvtui(hte_t *, sym_t *, sym_t *);
5191586Smarkmstatic	void	chkvtdi(hte_t *, sym_t *, sym_t *);
5291586Smarkmstatic	void	chkfaui(hte_t *, sym_t *, sym_t *);
5391586Smarkmstatic	void	chkau(hte_t *, int, sym_t *, sym_t *, pos_t *,
5491586Smarkm			   fcall_t *, fcall_t *, type_t *, type_t *);
5591586Smarkmstatic	void	chkrvu(hte_t *, sym_t *);
5691586Smarkmstatic	void	chkadecl(hte_t *, sym_t *, sym_t *);
5791586Smarkmstatic	void	printflike(hte_t *,fcall_t *, int, const char *, type_t **);
5891586Smarkmstatic	void	scanflike(hte_t *, fcall_t *, int, const char *, type_t **);
5991586Smarkmstatic	void	badfmt(hte_t *, fcall_t *);
6091586Smarkmstatic	void	inconarg(hte_t *, fcall_t *, int);
6191586Smarkmstatic	void	tofewarg(hte_t *, fcall_t *);
6291586Smarkmstatic	void	tomanyarg(hte_t *, fcall_t *);
6391586Smarkmstatic	int	eqtype(type_t *, type_t *, int, int, int, int *);
6491586Smarkmstatic	int	eqargs(type_t *, type_t *, int *);
6591586Smarkmstatic	int	mnoarg(type_t *, int *);
6612099Sjoerg
6712099Sjoerg
6812099Sjoerg/*
6912099Sjoerg * If there is a symbol named "main", mark it as used.
7012099Sjoerg */
7112099Sjoergvoid
7291586Smarkmmainused(void)
7312099Sjoerg{
7412099Sjoerg	hte_t	*hte;
7512099Sjoerg
7612099Sjoerg	if ((hte = hsearch("main", 0)) != NULL)
7712099Sjoerg		hte->h_used = 1;
7812099Sjoerg}
7912099Sjoerg
8012099Sjoerg/*
8112099Sjoerg * Performs all tests for a single name
8212099Sjoerg */
8312099Sjoergvoid
8491586Smarkmchkname(hte_t *hte)
8512099Sjoerg{
8612099Sjoerg	sym_t	*sym, *def, *pdecl, *decl;
8712099Sjoerg
8812099Sjoerg	if (uflag) {
8912099Sjoerg		chkund(hte);
9012099Sjoerg		chkdnu(hte);
9112099Sjoerg		if (xflag)
9212099Sjoerg			chkdnud(hte);
9312099Sjoerg	}
9412099Sjoerg	chkmd(hte);
9512099Sjoerg
9612099Sjoerg	/* Get definition, prototype declaration and declaration */
9712099Sjoerg	def = pdecl = decl = NULL;
9812099Sjoerg	for (sym = hte->h_syms; sym != NULL; sym = sym->s_nxt) {
9912099Sjoerg		if (def == NULL && (sym->s_def == DEF || sym->s_def == TDEF))
10012099Sjoerg			def = sym;
10112099Sjoerg		if (pdecl == NULL && sym->s_def == DECL &&
10212099Sjoerg		    TP(sym->s_type)->t_tspec == FUNC &&
10312099Sjoerg		    TP(sym->s_type)->t_proto) {
10412099Sjoerg			pdecl = sym;
10512099Sjoerg		}
10612099Sjoerg		if (decl == NULL && sym->s_def == DECL)
10712099Sjoerg			decl = sym;
10812099Sjoerg	}
10912099Sjoerg
11012099Sjoerg	/* A prototype is better than an old style declaration. */
11112099Sjoerg	if (pdecl != NULL)
11212099Sjoerg		decl = pdecl;
11312099Sjoerg
11412099Sjoerg	chkvtui(hte, def, decl);
11512099Sjoerg
11612099Sjoerg	chkvtdi(hte, def, decl);
11712099Sjoerg
11812099Sjoerg	chkfaui(hte, def, decl);
11912099Sjoerg
12012099Sjoerg	chkrvu(hte, def);
12112099Sjoerg
12212099Sjoerg	chkadecl(hte, def, decl);
12312099Sjoerg}
12412099Sjoerg
12512099Sjoerg/*
12612099Sjoerg * Print a warning if the name has been used, but not defined.
12712099Sjoerg */
12812099Sjoergstatic void
12991586Smarkmchkund(hte_t *hte)
13012099Sjoerg{
13112099Sjoerg	fcall_t	*fcall;
13212099Sjoerg	usym_t	*usym;
13312099Sjoerg
13412099Sjoerg	if (!hte->h_used || hte->h_def)
13512099Sjoerg		return;
13612099Sjoerg
13712099Sjoerg	if ((fcall = hte->h_calls) != NULL) {
13812099Sjoerg		/* %s used( %s ), but not defined */
13912099Sjoerg		msg(0, hte->h_name, mkpos(&fcall->f_pos));
14012099Sjoerg	} else if ((usym = hte->h_usyms) != NULL) {
14112099Sjoerg		/* %s used( %s ), but not defined */
14212099Sjoerg		msg(0, hte->h_name, mkpos(&usym->u_pos));
14312099Sjoerg	}
14412099Sjoerg}
14512099Sjoerg
14612099Sjoerg/*
14712099Sjoerg * Print a warning if the name has been defined, but never used.
14812099Sjoerg */
14912099Sjoergstatic void
15091586Smarkmchkdnu(hte_t *hte)
15112099Sjoerg{
15212099Sjoerg	sym_t	*sym;
15312099Sjoerg
15412099Sjoerg	if (!hte->h_def || hte->h_used)
15512099Sjoerg		return;
15612099Sjoerg
15712099Sjoerg	for (sym = hte->h_syms; sym != NULL; sym = sym->s_nxt) {
15812099Sjoerg		if (sym->s_def == DEF || sym->s_def == TDEF) {
15912099Sjoerg			/* %s defined( %s ), but never used */
16012099Sjoerg			msg(1, hte->h_name, mkpos(&sym->s_pos));
16112099Sjoerg			break;
16212099Sjoerg		}
16312099Sjoerg	}
16412099Sjoerg}
16512099Sjoerg
16612099Sjoerg/*
16791586Smarkm * Print a warning if the variable has been declared, but is not used
16812099Sjoerg * or defined.
16912099Sjoerg */
17012099Sjoergstatic void
17191586Smarkmchkdnud(hte_t *hte)
17212099Sjoerg{
17312099Sjoerg	sym_t	*sym;
17412099Sjoerg
17512099Sjoerg	if (hte->h_syms == NULL || hte->h_used || hte->h_def)
17612099Sjoerg		return;
17791586Smarkm
17891586Smarkm	sym = hte->h_syms;
17991586Smarkm	if (TP(sym->s_type)->t_tspec == FUNC)
18091586Smarkm		return;
18191586Smarkm
18291586Smarkm	if (sym->s_def != DECL)
18391586Smarkm		errx(1, "internal error: chkdnud() 1");
18491586Smarkm	/* %s declared( %s ), but never used or defined */
18591586Smarkm	msg(2, hte->h_name, mkpos(&sym->s_pos));
18612099Sjoerg}
18712099Sjoerg
18812099Sjoerg/*
18991586Smarkm * Print a warning if there is more than one definition for
19012099Sjoerg * this name.
19112099Sjoerg */
19212099Sjoergstatic void
19391586Smarkmchkmd(hte_t *hte)
19412099Sjoerg{
19512099Sjoerg	sym_t	*sym, *def1;
19612099Sjoerg	char	*pos1;
19712099Sjoerg
19812099Sjoerg	if (!hte->h_def)
19912099Sjoerg		return;
20012099Sjoerg
20112099Sjoerg	def1 = NULL;
20212099Sjoerg	for (sym = hte->h_syms; sym != NULL; sym = sym->s_nxt) {
20312099Sjoerg		/*
20412099Sjoerg		 * ANSI C allows tentative definitions of the same name in
20512099Sjoerg		 * only one compilation unit.
20612099Sjoerg		 */
20712099Sjoerg		if (sym->s_def != DEF && (!sflag || sym->s_def != TDEF))
20812099Sjoerg			continue;
20912099Sjoerg		if (def1 == NULL) {
21012099Sjoerg			def1 = sym;
21112099Sjoerg			continue;
21212099Sjoerg		}
21312099Sjoerg		pos1 = xstrdup(mkpos(&def1->s_pos));
21412099Sjoerg		/* %s multiply defined\t%s  ::  %s */
21512099Sjoerg		msg(3, hte->h_name, pos1, mkpos(&sym->s_pos));
21612099Sjoerg		free(pos1);
21712099Sjoerg	}
21812099Sjoerg}
21912099Sjoerg
22012099Sjoerg/*
22112099Sjoerg * Print a warning if the return value assumed for a function call
22212099Sjoerg * differs from the return value of the function definition or
22312099Sjoerg * function declaration.
22412099Sjoerg *
22512099Sjoerg * If no definition/declaration can be found, the assumed return values
22612099Sjoerg * are always int. So there is no need to compare with another function
22712099Sjoerg * call as it's done for function arguments.
22812099Sjoerg */
22912099Sjoergstatic void
23091586Smarkmchkvtui(hte_t *hte, sym_t *def, sym_t *decl)
23112099Sjoerg{
23212099Sjoerg	fcall_t	*call;
23312099Sjoerg	char	*pos1;
23412099Sjoerg	type_t	*tp1, *tp2;
23512099Sjoerg	/* LINTED (automatic hides external declaration: warn) */
23612099Sjoerg	int	warn, eq;
23712099Sjoerg	tspec_t	t1;
23812099Sjoerg
23912099Sjoerg	if (hte->h_calls == NULL)
24012099Sjoerg		return;
24112099Sjoerg
24212099Sjoerg	if (def == NULL)
24312099Sjoerg		def = decl;
24412099Sjoerg	if (def == NULL)
24512099Sjoerg		return;
24612099Sjoerg
24712099Sjoerg	t1 = (tp1 = TP(def->s_type)->t_subt)->t_tspec;
24812099Sjoerg	for (call = hte->h_calls; call != NULL; call = call->f_nxt) {
24912099Sjoerg		tp2 = TP(call->f_type)->t_subt;
25012099Sjoerg		eq = eqtype(tp1, tp2, 1, 0, 0, (warn = 0, &warn));
25112099Sjoerg		if (!call->f_rused) {
25212099Sjoerg			/* no return value used */
25312099Sjoerg			if ((t1 == STRUCT || t1 == UNION) && !eq) {
25412099Sjoerg				/*
25512099Sjoerg				 * If a function returns a struct or union it
25612099Sjoerg				 * must be declared to return a struct or
25712099Sjoerg				 * union, also if the return value is ignored.
25812099Sjoerg				 * This is necessary because the caller must
25912099Sjoerg				 * allocate stack space for the return value.
26012099Sjoerg				 * If it does not, the return value would over-
26112099Sjoerg				 * write other data.
26212099Sjoerg				 * XXX Following massage may be confusing
26312099Sjoerg				 * because it appears also if the return value
26412099Sjoerg				 * was declared inconsistently. But this
26512099Sjoerg				 * behaviour matches pcc based lint, so it is
26612099Sjoerg				 * accepted for now.
26712099Sjoerg				 */
26812099Sjoerg				pos1 = xstrdup(mkpos(&def->s_pos));
26912099Sjoerg				/* %s value must be decl. before use %s :: %s */
27012099Sjoerg				msg(17, hte->h_name,
27112099Sjoerg				    pos1, mkpos(&call->f_pos));
27212099Sjoerg				free(pos1);
27312099Sjoerg			}
27412099Sjoerg			continue;
27512099Sjoerg		}
27612099Sjoerg		if (!eq || (sflag && warn)) {
27712099Sjoerg			pos1 = xstrdup(mkpos(&def->s_pos));
27812099Sjoerg			/* %s value used inconsistenty\t%s  ::  %s */
27912099Sjoerg			msg(4, hte->h_name, pos1, mkpos(&call->f_pos));
28012099Sjoerg			free(pos1);
28112099Sjoerg		}
28212099Sjoerg	}
28312099Sjoerg}
28412099Sjoerg
28512099Sjoerg/*
28612099Sjoerg * Print a warning if a definition/declaration does not match another
28712099Sjoerg * definition/declaration of the same name. For functions, only the
28812099Sjoerg * types of return values are tested.
28912099Sjoerg */
29012099Sjoergstatic void
29191586Smarkmchkvtdi(hte_t *hte, sym_t *def, sym_t *decl)
29212099Sjoerg{
29312099Sjoerg	sym_t	*sym;
29412099Sjoerg	type_t	*tp1, *tp2;
29512099Sjoerg	/* LINTED (automatic hides external declaration: warn) */
29612099Sjoerg	int	eq, warn;
29712099Sjoerg	char	*pos1;
29812099Sjoerg
29912099Sjoerg	if (def == NULL)
30012099Sjoerg		def = decl;
30112099Sjoerg	if (def == NULL)
30212099Sjoerg		return;
30312099Sjoerg
30412099Sjoerg	tp1 = TP(def->s_type);
30512099Sjoerg	for (sym = hte->h_syms; sym != NULL; sym = sym->s_nxt) {
30612099Sjoerg		if (sym == def)
30712099Sjoerg			continue;
30812099Sjoerg		tp2 = TP(sym->s_type);
30912099Sjoerg		warn = 0;
31012099Sjoerg		if (tp1->t_tspec == FUNC && tp2->t_tspec == FUNC) {
31112099Sjoerg			eq = eqtype(tp1->t_subt, tp2->t_subt, 1, 0, 0, &warn);
31212099Sjoerg		} else {
31312099Sjoerg			eq = eqtype(tp1, tp2, 0, 0, 0, &warn);
31412099Sjoerg		}
31512099Sjoerg		if (!eq || (sflag && warn)) {
31612099Sjoerg			pos1 = xstrdup(mkpos(&def->s_pos));
31712099Sjoerg			/* %s value declared inconsistently\t%s  ::  %s */
31812099Sjoerg			msg(5, hte->h_name, pos1, mkpos(&sym->s_pos));
31912099Sjoerg			free(pos1);
32012099Sjoerg		}
32112099Sjoerg	}
32212099Sjoerg}
32312099Sjoerg
32412099Sjoerg/*
32512099Sjoerg * Print a warning if a function is called with arguments which does
32612099Sjoerg * not match the function definition, declaration or another call
32712099Sjoerg * of the same function.
32812099Sjoerg */
32912099Sjoergstatic void
33091586Smarkmchkfaui(hte_t *hte, sym_t *def, sym_t *decl)
33112099Sjoerg{
33212099Sjoerg	type_t	*tp1, *tp2, **ap1, **ap2;
33391586Smarkm	pos_t	*pos1p = NULL;
33412099Sjoerg	fcall_t	*calls, *call, *call1;
33512099Sjoerg	int	n, as;
33612099Sjoerg	char	*pos1;
33712099Sjoerg	arginf_t *ai;
33812099Sjoerg
33912099Sjoerg	if ((calls = hte->h_calls) == NULL)
34012099Sjoerg		return;
34112099Sjoerg
34212099Sjoerg	/*
34391586Smarkm	 * If we find a function definition, we use this for comparison,
34412099Sjoerg	 * otherwise the first prototype we can find. If there is no
34512099Sjoerg	 * definition or prototype declaration, the first function call
34612099Sjoerg	 * is used.
34712099Sjoerg	 */
34812099Sjoerg	tp1 = NULL;
34912099Sjoerg	call1 = NULL;
35012099Sjoerg	if (def != NULL) {
35112099Sjoerg		if ((tp1 = TP(def->s_type))->t_tspec != FUNC)
35212099Sjoerg			return;
35312099Sjoerg		pos1p = &def->s_pos;
35412099Sjoerg	} else if (decl != NULL && TP(decl->s_type)->t_proto) {
35512099Sjoerg		if ((tp1 = TP(decl->s_type))->t_tspec != FUNC)
35612099Sjoerg			return;
35712099Sjoerg		pos1p = &decl->s_pos;
35812099Sjoerg	}
35912099Sjoerg	if (tp1 == NULL) {
36012099Sjoerg		call1 = calls;
36112099Sjoerg		calls = calls->f_nxt;
36212099Sjoerg		if ((tp1 = TP(call1->f_type))->t_tspec != FUNC)
36312099Sjoerg			return;
36412099Sjoerg		pos1p = &call1->f_pos;
36512099Sjoerg	}
36612099Sjoerg
36712099Sjoerg	n = 1;
36812099Sjoerg	for (call = calls; call != NULL; call = call->f_nxt) {
36912099Sjoerg		if ((tp2 = TP(call->f_type))->t_tspec != FUNC)
37012099Sjoerg			continue;
37112099Sjoerg		ap1 = tp1->t_args;
37212099Sjoerg		ap2 = tp2->t_args;
37312099Sjoerg		n = 0;
37412099Sjoerg		while (*ap1 != NULL && *ap2 != NULL) {
37512099Sjoerg			if (def != NULL && def->s_va && n >= def->s_nva)
37612099Sjoerg				break;
37712099Sjoerg			n++;
37812099Sjoerg			chkau(hte, n, def, decl, pos1p, call1, call,
37912099Sjoerg			      *ap1, *ap2);
38012099Sjoerg			ap1++;
38112099Sjoerg			ap2++;
38212099Sjoerg		}
38312099Sjoerg		if (*ap1 == *ap2) {
38412099Sjoerg			/* equal # of arguments */
38512099Sjoerg		} else if (def != NULL && def->s_va && n >= def->s_nva) {
38612099Sjoerg			/*
38712099Sjoerg			 * function definition with VARARGS; The # of
38812099Sjoerg			 * arguments of the call must be at least as large
38912099Sjoerg			 * as the parameter of VARARGS.
39012099Sjoerg			 */
39112099Sjoerg		} else if (*ap2 != NULL && tp1->t_proto && tp1->t_vararg) {
39212099Sjoerg			/*
39312099Sjoerg			 * prototype with ... and function call with
39412099Sjoerg			 * at least the same # of arguments as declared
39512099Sjoerg			 * in the prototype.
39612099Sjoerg			 */
39712099Sjoerg		} else {
39812099Sjoerg			pos1 = xstrdup(mkpos(pos1p));
39912099Sjoerg			/* %s: variable # of args\t%s  ::  %s */
40012099Sjoerg			msg(7, hte->h_name, pos1, mkpos(&call->f_pos));
40112099Sjoerg			free(pos1);
40212099Sjoerg			continue;
40312099Sjoerg		}
40412099Sjoerg
40512099Sjoerg		/* perform SCANFLIKE/PRINTFLIKE tests */
40612099Sjoerg		if (def == NULL || (!def->s_prfl && !def->s_scfl))
40712099Sjoerg			continue;
40812099Sjoerg		as = def->s_prfl ? def->s_nprfl : def->s_nscfl;
40912099Sjoerg		for (ai = call->f_args; ai != NULL; ai = ai->a_nxt) {
41012099Sjoerg			if (ai->a_num == as)
41112099Sjoerg				break;
41212099Sjoerg		}
41312099Sjoerg		if (ai == NULL || !ai->a_fmt)
41412099Sjoerg			continue;
41512099Sjoerg		if (def->s_prfl) {
41612099Sjoerg			printflike(hte, call, n, ai->a_fstrg, ap2);
41712099Sjoerg		} else {
41812099Sjoerg			scanflike(hte, call, n, ai->a_fstrg, ap2);
41912099Sjoerg		}
42012099Sjoerg	}
42112099Sjoerg}
42212099Sjoerg
42312099Sjoerg/*
42412099Sjoerg * Check a single argument in a function call.
42512099Sjoerg *
42612099Sjoerg *  hte		a pointer to the hash table entry of the function
42712099Sjoerg *  n		the number of the argument (1..)
42812099Sjoerg *  def		the function definition or NULL
42912099Sjoerg *  decl	prototype declaration, old style declaration or NULL
43012099Sjoerg *  pos1p	position of definition, declaration of first call
43112099Sjoerg *  call1	first call, if both def and decl are old style def/decl
43212099Sjoerg *  call	checked call
43312099Sjoerg *  arg1	currently checked argument of def/decl/call1
43412099Sjoerg *  arg2	currently checked argument of call
43512099Sjoerg *
43612099Sjoerg */
43712099Sjoergstatic void
43891586Smarkmchkau(hte_t *hte, int n, sym_t *def, sym_t *decl, pos_t *pos1p,
43991586Smarkm	fcall_t *call1, fcall_t *call, type_t *arg1, type_t *arg2)
44012099Sjoerg{
44112099Sjoerg	/* LINTED (automatic hides external declaration: warn) */
44212099Sjoerg	int	promote, asgn, warn;
44312099Sjoerg	tspec_t	t1, t2;
44412099Sjoerg	arginf_t *ai, *ai1;
44512099Sjoerg	char	*pos1;
44612099Sjoerg
44712099Sjoerg	/*
44812099Sjoerg	 * If a function definition is available (def != NULL), we compair the
44912099Sjoerg	 * function call (call) with the definition. Otherwise, if a function
45012099Sjoerg	 * definition is available and it is not an old style definition
45112099Sjoerg	 * (decl != NULL && TP(decl->s_type)->t_proto), we compair the call
45212099Sjoerg	 * with this declaration. Otherwise we compair it with the first
45312099Sjoerg	 * call we have found (call1).
45412099Sjoerg	 */
45512099Sjoerg
45612099Sjoerg	/* arg1 must be promoted if it stems from an old style definition */
45712099Sjoerg	promote = def != NULL && def->s_osdef;
45812099Sjoerg
45912099Sjoerg	/*
46012099Sjoerg	 * If we compair with a definition or declaration, we must perform
46112099Sjoerg	 * the same checks for qualifiers in indirected types as in
46212099Sjoerg	 * assignments.
46312099Sjoerg	 */
46412099Sjoerg	asgn = def != NULL || (decl != NULL && TP(decl->s_type)->t_proto);
46512099Sjoerg
46612099Sjoerg	warn = 0;
46712099Sjoerg	if (eqtype(arg1, arg2, 1, promote, asgn, &warn) && (!sflag || !warn))
46812099Sjoerg		return;
46912099Sjoerg
47012099Sjoerg	/*
47112099Sjoerg	 * Other lint implementations print warnings as soon as the type
47212099Sjoerg	 * of an argument does not match exactly the expected type. The
47391586Smarkm	 * result are lots of warnings which are really not necessary.
47412099Sjoerg	 * We print a warning only if
47512099Sjoerg	 *   (0) at least one type is not an interger type and types differ
47612099Sjoerg	 *   (1) hflag is set and types differ
47712099Sjoerg	 *   (2) types differ, except in signedness
47812099Sjoerg	 * If the argument is an integer constant whose msb is not set,
47912099Sjoerg	 * signedness is ignored (e.g. 0 matches both signed and unsigned
48012099Sjoerg	 * int). This is with and without hflag.
48112099Sjoerg	 * If the argument is an integer constant with value 0 and the
48212099Sjoerg	 * expected argument is of type pointer and the width of the
48312099Sjoerg	 * interger constant is the same as the width of the pointer,
48412099Sjoerg	 * no warning is printed.
48512099Sjoerg	 */
48612099Sjoerg	t1 = arg1->t_tspec;
48712099Sjoerg	t2 = arg2->t_tspec;
48812099Sjoerg	if (isityp(t1) && isityp(t2) && !arg1->t_isenum && !arg2->t_isenum) {
48912099Sjoerg		if (promote) {
49012099Sjoerg			/*
49112099Sjoerg			 * XXX Here is a problem: Althrough it is possible to
49212099Sjoerg			 * pass an int where a char/short it expected, there
49312099Sjoerg			 * may be loss in significant digits. We should first
49412099Sjoerg			 * check for const arguments if they can be converted
49512099Sjoerg			 * into the original parameter type.
49612099Sjoerg			 */
49712099Sjoerg			if (t1 == FLOAT) {
49812099Sjoerg				t1 = DOUBLE;
49912099Sjoerg			} else if (t1 == CHAR || t1 == SCHAR) {
50012099Sjoerg				t1 = INT;
50112099Sjoerg			} else if (t1 == UCHAR) {
50212099Sjoerg				t1 = tflag ? UINT : INT;
50312099Sjoerg			} else if (t1 == SHORT) {
50412099Sjoerg				t1 = INT;
50512099Sjoerg			} else if (t1 == USHORT) {
50612099Sjoerg				/* CONSTCOND */
50712099Sjoerg				t1 = INT_MAX < USHRT_MAX || tflag ? UINT : INT;
50812099Sjoerg			}
50912099Sjoerg		}
51012099Sjoerg
51112099Sjoerg		if (styp(t1) == styp(t2)) {
51212099Sjoerg
51312099Sjoerg			/*
51412099Sjoerg			 * types differ only in signedness; get information
51512099Sjoerg			 * about arguments
51612099Sjoerg			 */
51712099Sjoerg
51812099Sjoerg			/*
51912099Sjoerg			 * treat a definition like a call with variable
52012099Sjoerg			 * arguments
52112099Sjoerg			 */
52212099Sjoerg			ai1 = call1 != NULL ? call1->f_args : NULL;
52312099Sjoerg
52412099Sjoerg			/*
52512099Sjoerg			 * if two calls are compared, ai1 is set to the
52612099Sjoerg			 * information for the n-th argument, if this was
52712099Sjoerg			 * a constant, otherwise to NULL
52812099Sjoerg			 */
52912099Sjoerg			for ( ; ai1 != NULL; ai1 = ai1->a_nxt) {
53012099Sjoerg				if (ai1->a_num == n)
53112099Sjoerg					break;
53212099Sjoerg			}
53312099Sjoerg			/*
53412099Sjoerg			 * ai is set to the information of the n-th arg
53512099Sjoerg			 * of the (second) call, if this was a constant,
53612099Sjoerg			 * otherwise to NULL
53712099Sjoerg			 */
53812099Sjoerg			for (ai = call->f_args; ai != NULL; ai = ai->a_nxt) {
53912099Sjoerg				if (ai->a_num == n)
54012099Sjoerg					break;
54112099Sjoerg			}
54212099Sjoerg
54312099Sjoerg			if (ai1 == NULL && ai == NULL) {
54412099Sjoerg				/* no constant at all */
54512099Sjoerg				if (!hflag)
54612099Sjoerg					return;
54712099Sjoerg			} else if (ai1 == NULL || ai == NULL) {
54812099Sjoerg				/* one constant */
54912099Sjoerg				if (ai == NULL)
55012099Sjoerg					ai = ai1;
55112099Sjoerg				if (ai->a_zero || ai->a_pcon)
55212099Sjoerg					/* same value in signed and unsigned */
55312099Sjoerg					return;
55412099Sjoerg				/* value (not representation) differently */
55512099Sjoerg			} else {
55612099Sjoerg				/*
55712099Sjoerg				 * two constants, one signed, one unsigned;
55812099Sjoerg				 * if the msb of one of the constants is set,
55912099Sjoerg				 * the argument is used inconsistently.
56012099Sjoerg				 */
56112099Sjoerg				if (!ai1->a_ncon && !ai->a_ncon)
56212099Sjoerg					return;
56312099Sjoerg			}
56412099Sjoerg		}
56512099Sjoerg
56691586Smarkm	} else if (t1 == PTR && isityp(t2)) {
56712099Sjoerg		for (ai = call->f_args; ai != NULL; ai = ai->a_nxt) {
56812099Sjoerg			if (ai->a_num == n)
56912099Sjoerg				break;
57012099Sjoerg		}
57191586Smarkm		/*
57291586Smarkm		 * Vendor implementations of lint (e.g. HP-UX, Digital UNIX)
57391586Smarkm		 * don't care about the size of the integer argument,
57491586Smarkm		 * only whether or not it is zero.  We do the same.
57591586Smarkm		 */
57612099Sjoerg		if (ai != NULL && ai->a_zero)
57712099Sjoerg			return;
57812099Sjoerg	}
57912099Sjoerg
58012099Sjoerg	pos1 = xstrdup(mkpos(pos1p));
58112099Sjoerg	/* %s, arg %d used inconsistently\t%s  ::  %s */
58212099Sjoerg	msg(6, hte->h_name, n, pos1, mkpos(&call->f_pos));
58312099Sjoerg	free(pos1);
58412099Sjoerg}
58512099Sjoerg
58612099Sjoerg/*
58712099Sjoerg * Compare the types in the NULL-terminated array ap with the format
58812099Sjoerg * string fmt.
58912099Sjoerg */
59012099Sjoergstatic void
59191586Smarkmprintflike(hte_t *hte, fcall_t *call, int n, const char *fmt, type_t **ap)
59212099Sjoerg{
59312099Sjoerg	const	char *fp;
59412099Sjoerg	int	fc;
59512099Sjoerg	int	fwidth, prec, left, sign, space, alt, zero;
59691586Smarkm	tspec_t	sz, t1, t2 = NOTSPEC;
59712099Sjoerg	type_t	*tp;
59812099Sjoerg
59912099Sjoerg	fp = fmt;
60012099Sjoerg	fc = *fp++;
60112099Sjoerg
60212099Sjoerg	for ( ; ; ) {
60312099Sjoerg		if (fc == '\0') {
60412099Sjoerg			if (*ap != NULL)
60512099Sjoerg				tomanyarg(hte, call);
60612099Sjoerg			break;
60712099Sjoerg		}
60812099Sjoerg		if (fc != '%') {
60912099Sjoerg			badfmt(hte, call);
61012099Sjoerg			break;
61112099Sjoerg		}
61212099Sjoerg		fc = *fp++;
61312099Sjoerg		fwidth = prec = left = sign = space = alt = zero = 0;
61412099Sjoerg		sz = NOTSPEC;
61512099Sjoerg
61612099Sjoerg		/* Flags */
61712099Sjoerg		for ( ; ; ) {
61812099Sjoerg			if (fc == '-') {
61912099Sjoerg				if (left)
62012099Sjoerg					break;
62112099Sjoerg				left = 1;
62212099Sjoerg			} else if (fc == '+') {
62312099Sjoerg				if (sign)
62412099Sjoerg					break;
62512099Sjoerg				sign = 1;
62612099Sjoerg			} else if (fc == ' ') {
62712099Sjoerg				if (space)
62812099Sjoerg					break;
62912099Sjoerg				space = 1;
63012099Sjoerg			} else if (fc == '#') {
63112099Sjoerg				if (alt)
63212099Sjoerg					break;
63312099Sjoerg				alt = 1;
63412099Sjoerg			} else if (fc == '0') {
63512099Sjoerg				if (zero)
63612099Sjoerg					break;
63712099Sjoerg				zero = 1;
63812099Sjoerg			} else {
63912099Sjoerg				break;
64012099Sjoerg			}
64112099Sjoerg			fc = *fp++;
64212099Sjoerg		}
64312099Sjoerg
64412099Sjoerg		/* field width */
64512099Sjoerg		if (isdigit(fc)) {
64612099Sjoerg			fwidth = 1;
64712099Sjoerg			do { fc = *fp++; } while (isdigit(fc)) ;
64812099Sjoerg		} else if (fc == '*') {
64912099Sjoerg			fwidth = 1;
65012099Sjoerg			fc = *fp++;
65112099Sjoerg			if ((tp = *ap++) == NULL) {
65212099Sjoerg				tofewarg(hte, call);
65312099Sjoerg				break;
65412099Sjoerg			}
65512099Sjoerg			n++;
65612099Sjoerg			if ((t1 = tp->t_tspec) != INT && (hflag || t1 != UINT))
65712099Sjoerg				inconarg(hte, call, n);
65812099Sjoerg		}
65912099Sjoerg
66012099Sjoerg		/* precision */
66112099Sjoerg		if (fc == '.') {
66212099Sjoerg			fc = *fp++;
66312099Sjoerg			prec = 1;
66412099Sjoerg			if (isdigit(fc)) {
66512099Sjoerg				do { fc = *fp++; } while (isdigit(fc));
66612099Sjoerg			} else if (fc == '*') {
66712099Sjoerg				fc = *fp++;
66812099Sjoerg				if ((tp = *ap++) == NULL) {
66912099Sjoerg					tofewarg(hte, call);
67012099Sjoerg					break;
67112099Sjoerg				}
67212099Sjoerg				n++;
67312099Sjoerg				if (tp->t_tspec != INT)
67412099Sjoerg					inconarg(hte, call, n);
67512099Sjoerg			} else {
67612099Sjoerg				badfmt(hte, call);
67712099Sjoerg				break;
67812099Sjoerg			}
67912099Sjoerg		}
68012099Sjoerg
68112099Sjoerg		if (fc == 'h') {
68212099Sjoerg			sz = SHORT;
68312099Sjoerg		} else if (fc == 'l') {
68412099Sjoerg			sz = LONG;
68512099Sjoerg		} else if (fc == 'q') {
68612099Sjoerg			sz = QUAD;
68712099Sjoerg		} else if (fc == 'L') {
68812099Sjoerg			sz = LDOUBLE;
68912099Sjoerg		}
69012099Sjoerg		if (sz != NOTSPEC)
69112099Sjoerg			fc = *fp++;
69212099Sjoerg
69312099Sjoerg		if (fc == '%') {
69412099Sjoerg			if (sz != NOTSPEC || left || sign || space ||
69512099Sjoerg			    alt || zero || prec || fwidth) {
69612099Sjoerg				badfmt(hte, call);
69712099Sjoerg			}
69812099Sjoerg			fc = *fp++;
69912099Sjoerg			continue;
70012099Sjoerg		}
70112099Sjoerg
70212099Sjoerg		if (fc == '\0') {
70312099Sjoerg			badfmt(hte, call);
70412099Sjoerg			break;
70512099Sjoerg		}
70612099Sjoerg
70712099Sjoerg		if ((tp = *ap++) == NULL) {
70812099Sjoerg			tofewarg(hte, call);
70912099Sjoerg			break;
71012099Sjoerg		}
71112099Sjoerg		n++;
71212099Sjoerg		if ((t1 = tp->t_tspec) == PTR)
71312099Sjoerg			t2 = tp->t_subt->t_tspec;
71412099Sjoerg
71512099Sjoerg		if (fc == 'd' || fc == 'i') {
71612099Sjoerg			if (alt || sz == LDOUBLE) {
71712099Sjoerg				badfmt(hte, call);
71812099Sjoerg				break;
71912099Sjoerg			}
72012099Sjoerg		int_conv:
72112099Sjoerg			if (sz == LONG) {
72212099Sjoerg				if (t1 != LONG && (hflag || t1 != ULONG))
72312099Sjoerg					inconarg(hte, call, n);
72412099Sjoerg			} else if (sz == QUAD) {
72512099Sjoerg				if (t1 != QUAD && (hflag || t1 != UQUAD))
72612099Sjoerg					inconarg(hte, call, n);
72712099Sjoerg			} else {
72812099Sjoerg				/*
72912099Sjoerg				 * SHORT is always promoted to INT, USHORT
73012099Sjoerg				 * to INT or UINT.
73112099Sjoerg				 */
73212099Sjoerg				if (t1 != INT && (hflag || t1 != UINT))
73312099Sjoerg					inconarg(hte, call, n);
73412099Sjoerg			}
73512099Sjoerg		} else if (fc == 'o' || fc == 'u' || fc == 'x' || fc == 'X') {
73612099Sjoerg			if ((alt && fc == 'u') || sz == LDOUBLE)
73712099Sjoerg				badfmt(hte, call);
73812099Sjoerg		uint_conv:
73912099Sjoerg			if (sz == LONG) {
74012099Sjoerg				if (t1 != ULONG && (hflag || t1 != LONG))
74112099Sjoerg					inconarg(hte, call, n);
74212099Sjoerg			} else if (sz == QUAD) {
74312099Sjoerg				if (t1 != UQUAD && (hflag || t1 != QUAD))
74412099Sjoerg					inconarg(hte, call, n);
74512099Sjoerg			} else if (sz == SHORT) {
74612099Sjoerg				/* USHORT was promoted to INT or UINT */
74712099Sjoerg				if (t1 != UINT && t1 != INT)
74812099Sjoerg					inconarg(hte, call, n);
74912099Sjoerg			} else {
75012099Sjoerg				if (t1 != UINT && (hflag || t1 != INT))
75112099Sjoerg					inconarg(hte, call, n);
75212099Sjoerg			}
75312099Sjoerg		} else if (fc == 'D' || fc == 'O' || fc == 'U') {
75412099Sjoerg			if ((alt && fc != 'O') || sz != NOTSPEC || !tflag)
75512099Sjoerg				badfmt(hte, call);
75612099Sjoerg			sz = LONG;
75712099Sjoerg			if (fc == 'D') {
75812099Sjoerg				goto int_conv;
75912099Sjoerg			} else {
76012099Sjoerg				goto uint_conv;
76112099Sjoerg			}
76212099Sjoerg		} else if (fc == 'f' || fc == 'e' || fc == 'E' ||
76312099Sjoerg			   fc == 'g' || fc == 'G') {
76412099Sjoerg			if (sz == NOTSPEC)
76512099Sjoerg				sz = DOUBLE;
76612099Sjoerg			if (sz != DOUBLE && sz != LDOUBLE)
76712099Sjoerg				badfmt(hte, call);
76812099Sjoerg			if (t1 != sz)
76912099Sjoerg				inconarg(hte, call, n);
77012099Sjoerg		} else if (fc == 'c') {
77112099Sjoerg			if (sz != NOTSPEC || alt || zero)
77212099Sjoerg				badfmt(hte, call);
77312099Sjoerg			if (t1 != INT)
77412099Sjoerg				inconarg(hte, call, n);
77512099Sjoerg		} else if (fc == 's') {
77612099Sjoerg			if (sz != NOTSPEC || alt || zero)
77712099Sjoerg				badfmt(hte, call);
77812099Sjoerg			if (t1 != PTR ||
77912099Sjoerg			    (t2 != CHAR && t2 != UCHAR && t2 != SCHAR)) {
78012099Sjoerg				inconarg(hte, call, n);
78112099Sjoerg			}
78212099Sjoerg		} else if (fc == 'p') {
78312099Sjoerg			if (fwidth || prec || sz != NOTSPEC || alt || zero)
78412099Sjoerg				badfmt(hte, call);
78512099Sjoerg			if (t1 != PTR || (hflag && t2 != VOID))
78612099Sjoerg				inconarg(hte, call, n);
78712099Sjoerg		} else if (fc == 'n') {
78812099Sjoerg			if (fwidth || prec || alt || zero || sz == LDOUBLE)
78912099Sjoerg				badfmt(hte, call);
79012099Sjoerg			if (t1 != PTR) {
79112099Sjoerg				inconarg(hte, call, n);
79212099Sjoerg			} else if (sz == LONG) {
79312099Sjoerg				if (t2 != LONG && t2 != ULONG)
79412099Sjoerg					inconarg(hte, call, n);
79512099Sjoerg			} else if (sz == SHORT) {
79612099Sjoerg				if (t2 != SHORT && t2 != USHORT)
79712099Sjoerg					inconarg(hte, call, n);
79812099Sjoerg			} else {
79912099Sjoerg				if (t2 != INT && t2 != UINT)
80012099Sjoerg					inconarg(hte, call, n);
80112099Sjoerg			}
80212099Sjoerg		} else {
80312099Sjoerg			badfmt(hte, call);
80412099Sjoerg			break;
80512099Sjoerg		}
80612099Sjoerg
80712099Sjoerg		fc = *fp++;
80812099Sjoerg	}
80912099Sjoerg}
81012099Sjoerg
81112099Sjoerg/*
81212099Sjoerg * Compare the types in the NULL-terminated array ap with the format
81312099Sjoerg * string fmt.
81412099Sjoerg */
81512099Sjoergstatic void
81691586Smarkmscanflike(hte_t *hte, fcall_t *call, int n, const char *fmt, type_t **ap)
81712099Sjoerg{
81812099Sjoerg	const	char *fp;
81912099Sjoerg	int	fc;
82012099Sjoerg	int	noasgn, fwidth;
82191586Smarkm	tspec_t	sz, t1 = NOTSPEC, t2 = NOTSPEC;
82291586Smarkm	type_t	*tp = NULL;
82312099Sjoerg
82412099Sjoerg	fp = fmt;
82512099Sjoerg	fc = *fp++;
82612099Sjoerg
82712099Sjoerg	for ( ; ; ) {
82812099Sjoerg		if (fc == '\0') {
82912099Sjoerg			if (*ap != NULL)
83012099Sjoerg				tomanyarg(hte, call);
83112099Sjoerg			break;
83212099Sjoerg		}
83312099Sjoerg		if (fc != '%') {
83412099Sjoerg			badfmt(hte, call);
83512099Sjoerg			break;
83612099Sjoerg		}
83712099Sjoerg		fc = *fp++;
83812099Sjoerg
83912099Sjoerg		noasgn = fwidth = 0;
84012099Sjoerg		sz = NOTSPEC;
84112099Sjoerg
84212099Sjoerg		if (fc == '*') {
84312099Sjoerg			noasgn = 1;
84412099Sjoerg			fc = *fp++;
84512099Sjoerg		}
84691586Smarkm
84712099Sjoerg		if (isdigit(fc)) {
84812099Sjoerg			fwidth = 1;
84912099Sjoerg			do { fc = *fp++; } while (isdigit(fc));
85012099Sjoerg		}
85112099Sjoerg
85212099Sjoerg		if (fc == 'h') {
85312099Sjoerg			sz = SHORT;
85412099Sjoerg		} else if (fc == 'l') {
85512099Sjoerg			sz = LONG;
85612099Sjoerg		} else if (fc == 'q') {
85712099Sjoerg			sz = QUAD;
85812099Sjoerg		} else if (fc == 'L') {
85912099Sjoerg			sz = LDOUBLE;
86012099Sjoerg		}
86112099Sjoerg		if (sz != NOTSPEC)
86212099Sjoerg			fc = *fp++;
86312099Sjoerg
86412099Sjoerg		if (fc == '%') {
86512099Sjoerg			if (sz != NOTSPEC || noasgn || fwidth)
86612099Sjoerg				badfmt(hte, call);
86712099Sjoerg			fc = *fp++;
86812099Sjoerg			continue;
86912099Sjoerg		}
87012099Sjoerg
87112099Sjoerg		if (!noasgn) {
87212099Sjoerg			if ((tp = *ap++) == NULL) {
87312099Sjoerg				tofewarg(hte, call);
87412099Sjoerg				break;
87512099Sjoerg			}
87612099Sjoerg			n++;
87712099Sjoerg			if ((t1 = tp->t_tspec) == PTR)
87812099Sjoerg				t2 = tp->t_subt->t_tspec;
87912099Sjoerg		}
88012099Sjoerg
88112099Sjoerg		if (fc == 'd' || fc == 'i' || fc == 'n') {
88212099Sjoerg			if (sz == LDOUBLE)
88312099Sjoerg				badfmt(hte, call);
88412099Sjoerg			if (sz != SHORT && sz != LONG && sz != QUAD)
88512099Sjoerg				sz = INT;
88612099Sjoerg		conv:
88712099Sjoerg			if (!noasgn) {
88812099Sjoerg				if (t1 != PTR) {
88912099Sjoerg					inconarg(hte, call, n);
89012099Sjoerg				} else if (t2 != styp(sz)) {
89112099Sjoerg					inconarg(hte, call, n);
89212099Sjoerg				} else if (hflag && t2 != sz) {
89312099Sjoerg					inconarg(hte, call, n);
89412099Sjoerg				} else if (tp->t_subt->t_const) {
89512099Sjoerg					inconarg(hte, call, n);
89612099Sjoerg				}
89712099Sjoerg			}
89812099Sjoerg		} else if (fc == 'o' || fc == 'u' || fc == 'x') {
89912099Sjoerg			if (sz == LDOUBLE)
90012099Sjoerg				badfmt(hte, call);
90112099Sjoerg			if (sz == SHORT) {
90212099Sjoerg				sz = USHORT;
90312099Sjoerg			} else if (sz == LONG) {
90412099Sjoerg				sz = ULONG;
90512099Sjoerg			} else if (sz == QUAD) {
90612099Sjoerg				sz = UQUAD;
90712099Sjoerg			} else {
90812099Sjoerg				sz = UINT;
90912099Sjoerg			}
91012099Sjoerg			goto conv;
91112099Sjoerg		} else if (fc == 'D') {
91212099Sjoerg			if (sz != NOTSPEC || !tflag)
91312099Sjoerg				badfmt(hte, call);
91412099Sjoerg			sz = LONG;
91512099Sjoerg			goto conv;
91612099Sjoerg		} else if (fc == 'O') {
91712099Sjoerg			if (sz != NOTSPEC || !tflag)
91812099Sjoerg				badfmt(hte, call);
91912099Sjoerg			sz = ULONG;
92012099Sjoerg			goto conv;
92112099Sjoerg		} else if (fc == 'X') {
92212099Sjoerg			/*
92312099Sjoerg			 * XXX valid in ANSI C, but in NetBSD's libc imple-
92412099Sjoerg			 * mented as "lx". Thats why it should be avoided.
92512099Sjoerg			 */
92612099Sjoerg			if (sz != NOTSPEC || !tflag)
92712099Sjoerg				badfmt(hte, call);
92812099Sjoerg			sz = ULONG;
92912099Sjoerg			goto conv;
93012099Sjoerg		} else if (fc == 'E') {
93112099Sjoerg			/*
93212099Sjoerg			 * XXX valid in ANSI C, but in NetBSD's libc imple-
93312099Sjoerg			 * mented as "lf". Thats why it should be avoided.
93412099Sjoerg			 */
93512099Sjoerg			if (sz != NOTSPEC || !tflag)
93612099Sjoerg				badfmt(hte, call);
93712099Sjoerg			sz = DOUBLE;
93812099Sjoerg			goto conv;
93912099Sjoerg		} else if (fc == 'F') {
94012099Sjoerg			/* XXX only for backward compatibility */
94112099Sjoerg			if (sz != NOTSPEC || !tflag)
94212099Sjoerg				badfmt(hte, call);
94312099Sjoerg			sz = DOUBLE;
94412099Sjoerg			goto conv;
94512099Sjoerg		} else if (fc == 'G') {
94612099Sjoerg			/*
94712099Sjoerg			 * XXX valid in ANSI C, but in NetBSD's libc not
94812099Sjoerg			 * implemented
94912099Sjoerg			 */
95012099Sjoerg			if (sz != NOTSPEC && sz != LONG && sz != LDOUBLE)
95112099Sjoerg				badfmt(hte, call);
95212099Sjoerg			goto fconv;
95312099Sjoerg		} else if (fc == 'e' || fc == 'f' || fc == 'g') {
95412099Sjoerg		fconv:
95512099Sjoerg			if (sz == NOTSPEC) {
95612099Sjoerg				sz = FLOAT;
95712099Sjoerg			} else if (sz == LONG) {
95812099Sjoerg				sz = DOUBLE;
95912099Sjoerg			} else if (sz != LDOUBLE) {
96012099Sjoerg				badfmt(hte, call);
96112099Sjoerg				sz = FLOAT;
96212099Sjoerg			}
96312099Sjoerg			goto conv;
96412099Sjoerg		} else if (fc == 's' || fc == '[' || fc == 'c') {
96512099Sjoerg			if (sz != NOTSPEC)
96612099Sjoerg				badfmt(hte, call);
96712099Sjoerg			if (fc == '[') {
96812099Sjoerg				if ((fc = *fp++) == '-') {
96912099Sjoerg					badfmt(hte, call);
97012099Sjoerg					fc = *fp++;
97112099Sjoerg				}
97212099Sjoerg				if (fc != ']') {
97312099Sjoerg					badfmt(hte, call);
97412099Sjoerg					if (fc == '\0')
97512099Sjoerg						break;
97612099Sjoerg				}
97712099Sjoerg			}
97812099Sjoerg			if (!noasgn) {
97912099Sjoerg				if (t1 != PTR) {
98012099Sjoerg					inconarg(hte, call, n);
98112099Sjoerg				} else if (t2 != CHAR && t2 != UCHAR &&
98212099Sjoerg					   t2 != SCHAR) {
98312099Sjoerg					inconarg(hte, call, n);
98412099Sjoerg				}
98512099Sjoerg			}
98612099Sjoerg		} else if (fc == 'p') {
98712099Sjoerg			if (sz != NOTSPEC)
98812099Sjoerg				badfmt(hte, call);
98912099Sjoerg			if (!noasgn) {
99012099Sjoerg				if (t1 != PTR || t2 != PTR) {
99112099Sjoerg					inconarg(hte, call, n);
99212099Sjoerg				} else if (tp->t_subt->t_subt->t_tspec!=VOID) {
99312099Sjoerg					if (hflag)
99412099Sjoerg						inconarg(hte, call, n);
99512099Sjoerg				}
99612099Sjoerg			}
99712099Sjoerg		} else {
99812099Sjoerg			badfmt(hte, call);
99912099Sjoerg			break;
100012099Sjoerg		}
100112099Sjoerg
100212099Sjoerg		fc = *fp++;
100312099Sjoerg	}
100412099Sjoerg}
100512099Sjoerg
100612099Sjoergstatic void
100791586Smarkmbadfmt(hte_t *hte, fcall_t *call)
100812099Sjoerg{
100991586Smarkm
101012099Sjoerg	/* %s: malformed format string\t%s */
101112099Sjoerg	msg(13, hte->h_name, mkpos(&call->f_pos));
101212099Sjoerg}
101312099Sjoerg
101412099Sjoergstatic void
101591586Smarkminconarg(hte_t *hte, fcall_t *call, int n)
101612099Sjoerg{
101791586Smarkm
101812099Sjoerg	/* %s, arg %d inconsistent with format\t%s(%d) */
101912099Sjoerg	msg(14, hte->h_name, n, mkpos(&call->f_pos));
102012099Sjoerg}
102112099Sjoerg
102212099Sjoergstatic void
102391586Smarkmtofewarg(hte_t *hte, fcall_t *call)
102412099Sjoerg{
102591586Smarkm
102612099Sjoerg	/* %s: too few args for format  \t%s */
102712099Sjoerg	msg(15, hte->h_name, mkpos(&call->f_pos));
102812099Sjoerg}
102912099Sjoerg
103012099Sjoergstatic void
103191586Smarkmtomanyarg(hte_t *hte, fcall_t *call)
103212099Sjoerg{
103391586Smarkm
103412099Sjoerg	/* %s: too many args for format  \t%s */
103512099Sjoerg	msg(16, hte->h_name, mkpos(&call->f_pos));
103612099Sjoerg}
103712099Sjoerg
103812099Sjoerg
103912099Sjoerg/*
104012099Sjoerg * Print warnings for return values which are used, but not returned,
104112099Sjoerg * or return values which are always or sometimes ignored.
104212099Sjoerg */
104312099Sjoergstatic void
104491586Smarkmchkrvu(hte_t *hte, sym_t *def)
104512099Sjoerg{
104612099Sjoerg	fcall_t	*call;
104712099Sjoerg	int	used, ignored;
104812099Sjoerg
104912099Sjoerg	if (def == NULL)
105012099Sjoerg		/* don't know wheter or not the functions returns a value */
105112099Sjoerg		return;
105212099Sjoerg
105312099Sjoerg	if (hte->h_calls == NULL)
105412099Sjoerg		return;
105512099Sjoerg
105612099Sjoerg	if (def->s_rval) {
105712099Sjoerg		/* function has return value */
105812099Sjoerg		used = ignored = 0;
105912099Sjoerg		for (call = hte->h_calls; call != NULL; call = call->f_nxt) {
106091586Smarkm			used |= call->f_rused || call->f_rdisc;
106112099Sjoerg			ignored |= !call->f_rused && !call->f_rdisc;
106212099Sjoerg		}
106312099Sjoerg		/*
106412099Sjoerg		 * XXX as soon as we are able to disable single warnings
106512099Sjoerg		 * the following dependencies from hflag should be removed.
106612099Sjoerg		 * but for now I do'nt want to be botherd by this warnings
106712099Sjoerg		 * which are almost always useless.
106812099Sjoerg		 */
106912099Sjoerg		if (!used && ignored) {
107012099Sjoerg			if (hflag)
107112099Sjoerg				/* %s returns value which is always ignored */
107212099Sjoerg				msg(8, hte->h_name);
107312099Sjoerg		} else if (used && ignored) {
107412099Sjoerg			if (hflag)
107512099Sjoerg				/* %s returns value which is sometimes ign. */
107612099Sjoerg				msg(9, hte->h_name);
107712099Sjoerg		}
107812099Sjoerg	} else {
107912099Sjoerg		/* function has no return value */
108012099Sjoerg		for (call = hte->h_calls; call != NULL; call = call->f_nxt) {
108112099Sjoerg			if (call->f_rused)
108212099Sjoerg				/* %s value is used( %s ), but none ret. */
108312099Sjoerg				msg(10, hte->h_name, mkpos(&call->f_pos));
108412099Sjoerg		}
108512099Sjoerg	}
108612099Sjoerg}
108712099Sjoerg
108812099Sjoerg/*
108912099Sjoerg * Print warnings for inconsistent argument declarations.
109012099Sjoerg */
109112099Sjoergstatic void
109291586Smarkmchkadecl(hte_t *hte, sym_t *def, sym_t *decl)
109312099Sjoerg{
109412099Sjoerg	/* LINTED (automatic hides external declaration: warn) */
109512099Sjoerg	int	osdef, eq, warn, n;
109612099Sjoerg	sym_t	*sym1, *sym;
109712099Sjoerg	type_t	**ap1, **ap2, *tp1, *tp2;
109812099Sjoerg	char	*pos1;
109912099Sjoerg	const	char *pos2;
110012099Sjoerg
110112099Sjoerg	osdef = 0;
110212099Sjoerg	if (def != NULL) {
110312099Sjoerg		osdef = def->s_osdef;
110412099Sjoerg		sym1 = def;
110512099Sjoerg	} else if (decl != NULL && TP(decl->s_type)->t_proto) {
110612099Sjoerg		sym1 = decl;
110712099Sjoerg	} else {
110812099Sjoerg		return;
110912099Sjoerg	}
111012099Sjoerg	if (TP(sym1->s_type)->t_tspec != FUNC)
111112099Sjoerg		return;
111212099Sjoerg
111312099Sjoerg	/*
111412099Sjoerg	 * XXX Prototypes should also be compared with old style function
111512099Sjoerg	 * declarations.
111612099Sjoerg	 */
111712099Sjoerg
111812099Sjoerg	for (sym = hte->h_syms; sym != NULL; sym = sym->s_nxt) {
111912099Sjoerg		if (sym == sym1 || !TP(sym->s_type)->t_proto)
112012099Sjoerg			continue;
112112099Sjoerg		ap1 = TP(sym1->s_type)->t_args;
112212099Sjoerg		ap2 = TP(sym->s_type)->t_args;
112312099Sjoerg		n = 0;
112412099Sjoerg		while (*ap1 != NULL && *ap2 != NULL) {
112512099Sjoerg			warn = 0;
112612099Sjoerg			eq = eqtype(*ap1, *ap2, 1, osdef, 0, &warn);
112712099Sjoerg			if (!eq || warn) {
112812099Sjoerg				pos1 = xstrdup(mkpos(&sym1->s_pos));
112912099Sjoerg				pos2 = mkpos(&sym->s_pos);
113012099Sjoerg				/* %s, arg %d declared inconsistently ... */
113112099Sjoerg				msg(11, hte->h_name, n + 1, pos1, pos2);
113212099Sjoerg				free(pos1);
113312099Sjoerg			}
113412099Sjoerg			n++;
113512099Sjoerg			ap1++;
113612099Sjoerg			ap2++;
113712099Sjoerg		}
113812099Sjoerg		if (*ap1 == *ap2) {
113912099Sjoerg			tp1 = TP(sym1->s_type);
114012099Sjoerg			tp2 = TP(sym->s_type);
114112099Sjoerg			if (tp1->t_vararg == tp2->t_vararg)
114212099Sjoerg				continue;
114312099Sjoerg			if (tp2->t_vararg &&
114412099Sjoerg			    sym1->s_va && sym1->s_nva == n && !sflag) {
114512099Sjoerg				continue;
114612099Sjoerg			}
114712099Sjoerg		}
114812099Sjoerg		/* %s: variable # of args declared\t%s  ::  %s */
114912099Sjoerg		pos1 = xstrdup(mkpos(&sym1->s_pos));
115012099Sjoerg		msg(12, hte->h_name, pos1, mkpos(&sym->s_pos));
115112099Sjoerg		free(pos1);
115212099Sjoerg	}
115312099Sjoerg}
115412099Sjoerg
115512099Sjoerg
115612099Sjoerg/*
115712099Sjoerg * Check compatibility of two types. Returns 1 if types are compatible,
115812099Sjoerg * otherwise 0.
115912099Sjoerg *
116012099Sjoerg * ignqual	if set, ignore qualifiers of outhermost type; used for
116112099Sjoerg *		function arguments
116291586Smarkm * promote	if set, promote left type before comparison; used for
116391586Smarkm *		comparisons of arguments with parameters of old style
116412099Sjoerg *		definitions
116512099Sjoerg * asgn		left indirected type must have at least the same qualifiers
116612099Sjoerg *		like right indirected type (for assignments and function
116712099Sjoerg *		arguments)
116812099Sjoerg * *warn	set to 1 if an old style declaration was compared with
116912099Sjoerg *		an incompatible prototype declaration
117012099Sjoerg */
117112099Sjoergstatic int
117291586Smarkmeqtype(type_t *tp1, type_t *tp2, int ignqual, int promot, int asgn, int *warn)
117312099Sjoerg{
117412099Sjoerg	tspec_t	t, to;
117512099Sjoerg	int	indir;
117612099Sjoerg
117712099Sjoerg	to = NOTSPEC;
117812099Sjoerg	indir = 0;
117912099Sjoerg
118012099Sjoerg	while (tp1 != NULL && tp2 != NULL) {
118112099Sjoerg
118212099Sjoerg		t = tp1->t_tspec;
118312099Sjoerg		if (promot) {
118412099Sjoerg			if (t == FLOAT) {
118512099Sjoerg				t = DOUBLE;
118612099Sjoerg			} else if (t == CHAR || t == SCHAR) {
118712099Sjoerg				t = INT;
118812099Sjoerg			} else if (t == UCHAR) {
118912099Sjoerg				t = tflag ? UINT : INT;
119012099Sjoerg			} else if (t == SHORT) {
119112099Sjoerg				t = INT;
119212099Sjoerg			} else if (t == USHORT) {
119312099Sjoerg				/* CONSTCOND */
119412099Sjoerg				t = INT_MAX < USHRT_MAX || tflag ? UINT : INT;
119512099Sjoerg			}
119612099Sjoerg		}
119712099Sjoerg
119812099Sjoerg		if (asgn && to == PTR) {
119912099Sjoerg			if (indir == 1 && (t == VOID || tp2->t_tspec == VOID))
120012099Sjoerg				return (1);
120112099Sjoerg		}
120291586Smarkm
120312099Sjoerg		if (t != tp2->t_tspec) {
120412099Sjoerg			/*
120512099Sjoerg			 * Give pointer to types which differ only in
120612099Sjoerg			 * signedness a chance if not sflag and not hflag.
120712099Sjoerg			 */
120812099Sjoerg			if (sflag || hflag || to != PTR)
120912099Sjoerg				return (0);
121012099Sjoerg			if (styp(t) != styp(tp2->t_tspec))
121112099Sjoerg				return (0);
121212099Sjoerg		}
121312099Sjoerg
121412099Sjoerg		if (tp1->t_isenum && tp2->t_isenum) {
121512099Sjoerg			if (tp1->t_istag && tp2->t_istag) {
121612099Sjoerg				return (tp1->t_tag == tp2->t_tag);
121712099Sjoerg			} else if (tp1->t_istynam && tp2->t_istynam) {
121812099Sjoerg				return (tp1->t_tynam == tp2->t_tynam);
121991586Smarkm			} else if (tp1->t_isuniqpos && tp2->t_isuniqpos) {
122091586Smarkm				return (tp1->t_uniqpos.p_line ==
122191586Smarkm				      tp2->t_uniqpos.p_line &&
122291586Smarkm				    tp1->t_uniqpos.p_file ==
122391586Smarkm				      tp2->t_uniqpos.p_file &&
122491586Smarkm				    tp1->t_uniqpos.p_uniq ==
122591586Smarkm				      tp2->t_uniqpos.p_uniq);
122612099Sjoerg			} else {
122712099Sjoerg				return (0);
122812099Sjoerg			}
122912099Sjoerg		}
123012099Sjoerg
123112099Sjoerg		/*
123212099Sjoerg		 * XXX Handle combinations of enum and int if eflag is set.
123312099Sjoerg		 * But note: enum and 0 should be allowed.
123412099Sjoerg		 */
123512099Sjoerg
123612099Sjoerg		if (asgn && indir == 1) {
123712099Sjoerg			if (!tp1->t_const && tp2->t_const)
123812099Sjoerg				return (0);
123912099Sjoerg			if (!tp1->t_volatile && tp2->t_volatile)
124012099Sjoerg				return (0);
124112099Sjoerg		} else if (!ignqual && !tflag) {
124212099Sjoerg			if (tp1->t_const != tp2->t_const)
124312099Sjoerg				return (0);
124412099Sjoerg			if (tp1->t_const != tp2->t_const)
124512099Sjoerg				return (0);
124612099Sjoerg		}
124712099Sjoerg
124812099Sjoerg		if (t == STRUCT || t == UNION) {
124912099Sjoerg			if (tp1->t_istag && tp2->t_istag) {
125012099Sjoerg				return (tp1->t_tag == tp2->t_tag);
125112099Sjoerg			} else if (tp1->t_istynam && tp2->t_istynam) {
125212099Sjoerg				return (tp1->t_tynam == tp2->t_tynam);
125391586Smarkm			} else if (tp1->t_isuniqpos && tp2->t_isuniqpos) {
125491586Smarkm				return (tp1->t_uniqpos.p_line ==
125591586Smarkm				      tp2->t_uniqpos.p_line &&
125691586Smarkm				    tp1->t_uniqpos.p_file ==
125791586Smarkm				      tp2->t_uniqpos.p_file &&
125891586Smarkm				    tp1->t_uniqpos.p_uniq ==
125991586Smarkm				      tp2->t_uniqpos.p_uniq);
126012099Sjoerg			} else {
126112099Sjoerg				return (0);
126212099Sjoerg			}
126312099Sjoerg		}
126412099Sjoerg
126512099Sjoerg		if (t == ARRAY && tp1->t_dim != tp2->t_dim) {
126612099Sjoerg			if (tp1->t_dim != 0 && tp2->t_dim != 0)
126712099Sjoerg				return (0);
126812099Sjoerg		}
126912099Sjoerg
127012099Sjoerg		if (t == FUNC) {
127112099Sjoerg			if (tp1->t_proto && tp2->t_proto) {
127212099Sjoerg				if (!eqargs(tp1, tp2, warn))
127312099Sjoerg					return (0);
127412099Sjoerg			} else if (tp1->t_proto) {
127512099Sjoerg				if (!mnoarg(tp1, warn))
127612099Sjoerg					return (0);
127712099Sjoerg			} else if (tp2->t_proto) {
127812099Sjoerg				if (!mnoarg(tp2, warn))
127912099Sjoerg					return (0);
128012099Sjoerg			}
128112099Sjoerg		}
128212099Sjoerg
128312099Sjoerg		tp1 = tp1->t_subt;
128412099Sjoerg		tp2 = tp2->t_subt;
128512099Sjoerg		ignqual = promot = 0;
128612099Sjoerg		to = t;
128712099Sjoerg		indir++;
128812099Sjoerg
128912099Sjoerg	}
129012099Sjoerg
129112099Sjoerg	return (tp1 == tp2);
129212099Sjoerg}
129312099Sjoerg
129412099Sjoerg/*
129512099Sjoerg * Compares arguments of two prototypes
129612099Sjoerg */
129712099Sjoergstatic int
129891586Smarkmeqargs(type_t *tp1, type_t *tp2, int *warn)
129912099Sjoerg{
130012099Sjoerg	type_t	**a1, **a2;
130112099Sjoerg
130212099Sjoerg	if (tp1->t_vararg != tp2->t_vararg)
130312099Sjoerg		return (0);
130412099Sjoerg
130512099Sjoerg	a1 = tp1->t_args;
130612099Sjoerg	a2 = tp2->t_args;
130712099Sjoerg
130812099Sjoerg	while (*a1 != NULL && *a2 != NULL) {
130912099Sjoerg
131012099Sjoerg		if (eqtype(*a1, *a2, 1, 0, 0, warn) == 0)
131112099Sjoerg			return (0);
131212099Sjoerg
131312099Sjoerg		a1++;
131412099Sjoerg		a2++;
131512099Sjoerg
131612099Sjoerg	}
131712099Sjoerg
131812099Sjoerg	return (*a1 == *a2);
131912099Sjoerg}
132012099Sjoerg
132112099Sjoerg/*
132212099Sjoerg * mnoarg() (matches functions with no argument type information)
132312099Sjoerg * returns 1 if all parameters of a prototype are compatible with
132412099Sjoerg * and old style function declaration.
132512099Sjoerg * This is the case if following conditions are met:
132612099Sjoerg *	1. the prototype must have a fixed number of parameters
132712099Sjoerg *	2. no parameter is of type float
132812099Sjoerg *	3. no parameter is converted to another type if integer promotion
132912099Sjoerg *	   is applied on it
133012099Sjoerg */
133112099Sjoergstatic int
133291586Smarkmmnoarg(type_t *tp, int *warn)
133312099Sjoerg{
133412099Sjoerg	type_t	**arg;
133512099Sjoerg	tspec_t	t;
133612099Sjoerg
133712099Sjoerg	if (tp->t_vararg && warn != NULL)
133812099Sjoerg		*warn = 1;
133912099Sjoerg	for (arg = tp->t_args; *arg != NULL; arg++) {
134012099Sjoerg		if ((t = (*arg)->t_tspec) == FLOAT)
134112099Sjoerg			return (0);
134212099Sjoerg		if (t == CHAR || t == SCHAR || t == UCHAR)
134312099Sjoerg			return (0);
134412099Sjoerg		if (t == SHORT || t == USHORT)
134512099Sjoerg			return (0);
134612099Sjoerg	}
134712099Sjoerg	return (1);
134812099Sjoerg}
1349