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