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