Annotation of src/usr.bin/xlint/lint2/chk.c, Revision 1.33
1.33 ! rillig 1: /* $NetBSD: chk.c,v 1.32 2021/01/04 22:26:51 rillig Exp $ */
1.2 cgd 2:
1.1 cgd 3: /*
1.3 cgd 4: * Copyright (c) 1996 Christopher G. Demetriou. All Rights Reserved.
1.1 cgd 5: * Copyright (c) 1994, 1995 Jochen Pohl
6: * All Rights Reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. All advertising materials mentioning features or use of this software
17: * must display the following acknowledgement:
18: * This product includes software developed by Jochen Pohl for
19: * The NetBSD Project.
20: * 4. The name of the author may not be used to endorse or promote products
21: * derived from this software without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33: */
34:
1.17 jmc 35: #if HAVE_NBTOOL_CONFIG_H
36: #include "nbtool_config.h"
37: #endif
38:
1.5 christos 39: #include <sys/cdefs.h>
1.16 tv 40: #if defined(__RCSID) && !defined(lint)
1.33 ! rillig 41: __RCSID("$NetBSD: chk.c,v 1.32 2021/01/04 22:26:51 rillig Exp $");
1.1 cgd 42: #endif
43:
44: #include <ctype.h>
45: #include <limits.h>
1.15 tv 46: #include <stdlib.h>
1.25 rillig 47: #include <string.h>
1.1 cgd 48:
49: #include "lint2.h"
50:
1.10 lukem 51: static void chkund(hte_t *);
52: static void chkdnu(hte_t *);
53: static void chkdnud(hte_t *);
54: static void chkmd(hte_t *);
55: static void chkvtui(hte_t *, sym_t *, sym_t *);
56: static void chkvtdi(hte_t *, sym_t *, sym_t *);
57: static void chkfaui(hte_t *, sym_t *, sym_t *);
58: static void chkau(hte_t *, int, sym_t *, sym_t *, pos_t *,
59: fcall_t *, fcall_t *, type_t *, type_t *);
60: static void chkrvu(hte_t *, sym_t *);
61: static void chkadecl(hte_t *, sym_t *, sym_t *);
62: static void printflike(hte_t *,fcall_t *, int, const char *, type_t **);
63: static void scanflike(hte_t *, fcall_t *, int, const char *, type_t **);
64: static void badfmt(hte_t *, fcall_t *);
65: static void inconarg(hte_t *, fcall_t *, int);
66: static void tofewarg(hte_t *, fcall_t *);
67: static void tomanyarg(hte_t *, fcall_t *);
68: static int eqtype(type_t *, type_t *, int, int, int, int *);
69: static int eqargs(type_t *, type_t *, int *);
70: static int mnoarg(type_t *, int *);
1.1 cgd 71:
72:
73: /*
74: * If there is a symbol named "main", mark it as used.
75: */
76: void
1.10 lukem 77: mainused(void)
1.1 cgd 78: {
79: hte_t *hte;
80:
81: if ((hte = hsearch("main", 0)) != NULL)
82: hte->h_used = 1;
83: }
84:
85: /*
86: * Performs all tests for a single name
87: */
88: void
1.10 lukem 89: chkname(hte_t *hte)
1.1 cgd 90: {
91: sym_t *sym, *def, *pdecl, *decl;
92:
93: if (uflag) {
94: chkund(hte);
95: chkdnu(hte);
96: if (xflag)
97: chkdnud(hte);
98: }
99: chkmd(hte);
100:
101: /* Get definition, prototype declaration and declaration */
102: def = pdecl = decl = NULL;
1.28 rillig 103: for (sym = hte->h_syms; sym != NULL; sym = sym->s_next) {
1.1 cgd 104: if (def == NULL && (sym->s_def == DEF || sym->s_def == TDEF))
105: def = sym;
106: if (pdecl == NULL && sym->s_def == DECL &&
107: TP(sym->s_type)->t_tspec == FUNC &&
108: TP(sym->s_type)->t_proto) {
109: pdecl = sym;
110: }
111: if (decl == NULL && sym->s_def == DECL)
112: decl = sym;
113: }
114:
115: /* A prototype is better than an old style declaration. */
116: if (pdecl != NULL)
117: decl = pdecl;
118:
119: chkvtui(hte, def, decl);
120:
121: chkvtdi(hte, def, decl);
122:
123: chkfaui(hte, def, decl);
124:
125: chkrvu(hte, def);
126:
127: chkadecl(hte, def, decl);
128: }
129:
130: /*
131: * Print a warning if the name has been used, but not defined.
132: */
133: static void
1.10 lukem 134: chkund(hte_t *hte)
1.1 cgd 135: {
136: fcall_t *fcall;
137: usym_t *usym;
138:
139: if (!hte->h_used || hte->h_def)
140: return;
141:
142: if ((fcall = hte->h_calls) != NULL) {
143: /* %s used( %s ), but not defined */
144: msg(0, hte->h_name, mkpos(&fcall->f_pos));
145: } else if ((usym = hte->h_usyms) != NULL) {
146: /* %s used( %s ), but not defined */
147: msg(0, hte->h_name, mkpos(&usym->u_pos));
148: }
149: }
150:
151: /*
152: * Print a warning if the name has been defined, but never used.
153: */
154: static void
1.10 lukem 155: chkdnu(hte_t *hte)
1.1 cgd 156: {
157: sym_t *sym;
158:
159: if (!hte->h_def || hte->h_used)
160: return;
161:
1.28 rillig 162: for (sym = hte->h_syms; sym != NULL; sym = sym->s_next) {
1.1 cgd 163: if (sym->s_def == DEF || sym->s_def == TDEF) {
164: /* %s defined( %s ), but never used */
165: msg(1, hte->h_name, mkpos(&sym->s_pos));
166: break;
167: }
168: }
169: }
170:
171: /*
1.4 cgd 172: * Print a warning if the variable has been declared, but is not used
1.1 cgd 173: * or defined.
174: */
175: static void
1.10 lukem 176: chkdnud(hte_t *hte)
1.1 cgd 177: {
178: sym_t *sym;
179:
180: if (hte->h_syms == NULL || hte->h_used || hte->h_def)
181: return;
1.4 cgd 182:
183: sym = hte->h_syms;
184: if (TP(sym->s_type)->t_tspec == FUNC)
185: return;
186:
187: if (sym->s_def != DECL)
188: errx(1, "internal error: chkdnud() 1");
189: /* %s declared( %s ), but never used or defined */
190: msg(2, hte->h_name, mkpos(&sym->s_pos));
1.1 cgd 191: }
192:
193: /*
1.12 wiz 194: * Print a warning if there is more than one definition for
1.1 cgd 195: * this name.
196: */
197: static void
1.10 lukem 198: chkmd(hte_t *hte)
1.1 cgd 199: {
200: sym_t *sym, *def1;
201: char *pos1;
202:
203: if (!hte->h_def)
204: return;
205:
206: def1 = NULL;
1.28 rillig 207: for (sym = hte->h_syms; sym != NULL; sym = sym->s_next) {
1.1 cgd 208: /*
209: * ANSI C allows tentative definitions of the same name in
210: * only one compilation unit.
211: */
212: if (sym->s_def != DEF && (!sflag || sym->s_def != TDEF))
213: continue;
1.23 christos 214: if (sym->s_inline)
215: continue;
1.1 cgd 216: if (def1 == NULL) {
217: def1 = sym;
218: continue;
219: }
220: pos1 = xstrdup(mkpos(&def1->s_pos));
221: /* %s multiply defined\t%s :: %s */
222: msg(3, hte->h_name, pos1, mkpos(&sym->s_pos));
223: free(pos1);
224: }
225: }
226:
227: /*
228: * Print a warning if the return value assumed for a function call
229: * differs from the return value of the function definition or
230: * function declaration.
231: *
232: * If no definition/declaration can be found, the assumed return values
233: * are always int. So there is no need to compare with another function
234: * call as it's done for function arguments.
235: */
236: static void
1.10 lukem 237: chkvtui(hte_t *hte, sym_t *def, sym_t *decl)
1.1 cgd 238: {
239: fcall_t *call;
240: char *pos1;
241: type_t *tp1, *tp2;
1.20 lukem 242: int dowarn, eq;
1.1 cgd 243: tspec_t t1;
244:
245: if (hte->h_calls == NULL)
246: return;
247:
248: if (def == NULL)
249: def = decl;
250: if (def == NULL)
251: return;
252:
253: t1 = (tp1 = TP(def->s_type)->t_subt)->t_tspec;
1.29 rillig 254: for (call = hte->h_calls; call != NULL; call = call->f_next) {
1.1 cgd 255: tp2 = TP(call->f_type)->t_subt;
1.20 lukem 256: eq = eqtype(tp1, tp2, 1, 0, 0, (dowarn = 0, &dowarn));
1.1 cgd 257: if (!call->f_rused) {
258: /* no return value used */
259: if ((t1 == STRUCT || t1 == UNION) && !eq) {
260: /*
261: * If a function returns a struct or union it
262: * must be declared to return a struct or
263: * union, also if the return value is ignored.
264: * This is necessary because the caller must
265: * allocate stack space for the return value.
266: * If it does not, the return value would over-
267: * write other data.
268: * XXX Following massage may be confusing
269: * because it appears also if the return value
270: * was declared inconsistently. But this
271: * behaviour matches pcc based lint, so it is
272: * accepted for now.
273: */
274: pos1 = xstrdup(mkpos(&def->s_pos));
275: /* %s value must be decl. before use %s :: %s */
276: msg(17, hte->h_name,
277: pos1, mkpos(&call->f_pos));
278: free(pos1);
279: }
280: continue;
281: }
1.20 lukem 282: if (!eq || (sflag && dowarn)) {
1.1 cgd 283: pos1 = xstrdup(mkpos(&def->s_pos));
1.32 rillig 284: /* %s value used inconsistently\t%s :: %s */
1.1 cgd 285: msg(4, hte->h_name, pos1, mkpos(&call->f_pos));
286: free(pos1);
287: }
288: }
289: }
290:
291: /*
292: * Print a warning if a definition/declaration does not match another
293: * definition/declaration of the same name. For functions, only the
294: * types of return values are tested.
295: */
296: static void
1.10 lukem 297: chkvtdi(hte_t *hte, sym_t *def, sym_t *decl)
1.1 cgd 298: {
299: sym_t *sym;
300: type_t *tp1, *tp2;
1.20 lukem 301: int eq, dowarn;
1.1 cgd 302: char *pos1;
303:
304: if (def == NULL)
305: def = decl;
306: if (def == NULL)
307: return;
308:
309: tp1 = TP(def->s_type);
1.28 rillig 310: for (sym = hte->h_syms; sym != NULL; sym = sym->s_next) {
1.19 christos 311: type_t *xt1, *xt2;
1.1 cgd 312: if (sym == def)
313: continue;
314: tp2 = TP(sym->s_type);
1.20 lukem 315: dowarn = 0;
1.1 cgd 316: if (tp1->t_tspec == FUNC && tp2->t_tspec == FUNC) {
1.19 christos 317: eq = eqtype(xt1 = tp1->t_subt, xt2 = tp2->t_subt,
1.20 lukem 318: 1, 0, 0, &dowarn);
1.1 cgd 319: } else {
1.20 lukem 320: eq = eqtype(xt1 = tp1, xt2 = tp2, 0, 0, 0, &dowarn);
1.1 cgd 321: }
1.20 lukem 322: if (!eq || (sflag && dowarn)) {
1.1 cgd 323: pos1 = xstrdup(mkpos(&def->s_pos));
324: /* %s value declared inconsistently\t%s :: %s */
1.31 rillig 325: msg(5, hte->h_name, type_name(xt1), type_name(xt2),
326: pos1, mkpos(&sym->s_pos));
1.1 cgd 327: free(pos1);
328: }
329: }
330: }
331:
332: /*
333: * Print a warning if a function is called with arguments which does
334: * not match the function definition, declaration or another call
335: * of the same function.
336: */
337: static void
1.10 lukem 338: chkfaui(hte_t *hte, sym_t *def, sym_t *decl)
1.1 cgd 339: {
340: type_t *tp1, *tp2, **ap1, **ap2;
1.5 christos 341: pos_t *pos1p = NULL;
1.1 cgd 342: fcall_t *calls, *call, *call1;
343: int n, as;
344: char *pos1;
345: arginf_t *ai;
346:
347: if ((calls = hte->h_calls) == NULL)
348: return;
349:
350: /*
1.7 mycroft 351: * If we find a function definition, we use this for comparison,
1.1 cgd 352: * otherwise the first prototype we can find. If there is no
353: * definition or prototype declaration, the first function call
354: * is used.
355: */
356: tp1 = NULL;
357: call1 = NULL;
358: if (def != NULL) {
359: if ((tp1 = TP(def->s_type))->t_tspec != FUNC)
360: return;
361: pos1p = &def->s_pos;
362: } else if (decl != NULL && TP(decl->s_type)->t_proto) {
363: if ((tp1 = TP(decl->s_type))->t_tspec != FUNC)
364: return;
365: pos1p = &decl->s_pos;
366: }
367: if (tp1 == NULL) {
368: call1 = calls;
1.29 rillig 369: calls = calls->f_next;
1.1 cgd 370: if ((tp1 = TP(call1->f_type))->t_tspec != FUNC)
371: return;
372: pos1p = &call1->f_pos;
373: }
374:
375: n = 1;
1.29 rillig 376: for (call = calls; call != NULL; call = call->f_next) {
1.1 cgd 377: if ((tp2 = TP(call->f_type))->t_tspec != FUNC)
378: continue;
379: ap1 = tp1->t_args;
380: ap2 = tp2->t_args;
381: n = 0;
382: while (*ap1 != NULL && *ap2 != NULL) {
383: if (def != NULL && def->s_va && n >= def->s_nva)
384: break;
385: n++;
386: chkau(hte, n, def, decl, pos1p, call1, call,
387: *ap1, *ap2);
388: ap1++;
389: ap2++;
390: }
391: if (*ap1 == *ap2) {
392: /* equal # of arguments */
393: } else if (def != NULL && def->s_va && n >= def->s_nva) {
394: /*
395: * function definition with VARARGS; The # of
396: * arguments of the call must be at least as large
397: * as the parameter of VARARGS.
398: */
399: } else if (*ap2 != NULL && tp1->t_proto && tp1->t_vararg) {
400: /*
401: * prototype with ... and function call with
402: * at least the same # of arguments as declared
403: * in the prototype.
404: */
405: } else {
406: pos1 = xstrdup(mkpos(pos1p));
407: /* %s: variable # of args\t%s :: %s */
408: msg(7, hte->h_name, pos1, mkpos(&call->f_pos));
409: free(pos1);
410: continue;
411: }
412:
413: /* perform SCANFLIKE/PRINTFLIKE tests */
414: if (def == NULL || (!def->s_prfl && !def->s_scfl))
415: continue;
416: as = def->s_prfl ? def->s_nprfl : def->s_nscfl;
1.29 rillig 417: for (ai = call->f_args; ai != NULL; ai = ai->a_next) {
1.1 cgd 418: if (ai->a_num == as)
419: break;
420: }
421: if (ai == NULL || !ai->a_fmt)
422: continue;
423: if (def->s_prfl) {
424: printflike(hte, call, n, ai->a_fstrg, ap2);
425: } else {
426: scanflike(hte, call, n, ai->a_fstrg, ap2);
427: }
428: }
429: }
430:
431: /*
432: * Check a single argument in a function call.
433: *
434: * hte a pointer to the hash table entry of the function
435: * n the number of the argument (1..)
436: * def the function definition or NULL
437: * decl prototype declaration, old style declaration or NULL
438: * pos1p position of definition, declaration of first call
439: * call1 first call, if both def and decl are old style def/decl
440: * call checked call
441: * arg1 currently checked argument of def/decl/call1
442: * arg2 currently checked argument of call
443: *
444: */
445: static void
1.10 lukem 446: chkau(hte_t *hte, int n, sym_t *def, sym_t *decl, pos_t *pos1p,
447: fcall_t *call1, fcall_t *call, type_t *arg1, type_t *arg2)
1.1 cgd 448: {
1.20 lukem 449: int promote, asgn, dowarn;
1.1 cgd 450: tspec_t t1, t2;
451: arginf_t *ai, *ai1;
452: char *pos1;
453:
454: /*
1.32 rillig 455: * If a function definition is available (def != NULL), we compare the
1.1 cgd 456: * function call (call) with the definition. Otherwise, if a function
457: * definition is available and it is not an old style definition
1.32 rillig 458: * (decl != NULL && TP(decl->s_type)->t_proto), we compare the call
459: * with this declaration. Otherwise we compare it with the first
1.1 cgd 460: * call we have found (call1).
461: */
462:
463: /* arg1 must be promoted if it stems from an old style definition */
464: promote = def != NULL && def->s_osdef;
465:
466: /*
1.32 rillig 467: * If we compare with a definition or declaration, we must perform
1.1 cgd 468: * the same checks for qualifiers in indirected types as in
469: * assignments.
470: */
471: asgn = def != NULL || (decl != NULL && TP(decl->s_type)->t_proto);
472:
1.20 lukem 473: dowarn = 0;
474: if (eqtype(arg1, arg2, 1, promote, asgn, &dowarn) && (!sflag || !dowarn))
1.1 cgd 475: return;
476:
477: /*
478: * Other lint implementations print warnings as soon as the type
479: * of an argument does not match exactly the expected type. The
1.11 wiz 480: * result are lots of warnings which are really not necessary.
1.1 cgd 481: * We print a warning only if
1.32 rillig 482: * (0) at least one type is not an integer type and types differ
1.1 cgd 483: * (1) hflag is set and types differ
484: * (2) types differ, except in signedness
485: * If the argument is an integer constant whose msb is not set,
486: * signedness is ignored (e.g. 0 matches both signed and unsigned
487: * int). This is with and without hflag.
488: * If the argument is an integer constant with value 0 and the
489: * expected argument is of type pointer and the width of the
1.32 rillig 490: * integer constant is the same as the width of the pointer,
1.1 cgd 491: * no warning is printed.
492: */
493: t1 = arg1->t_tspec;
494: t2 = arg2->t_tspec;
1.33 ! rillig 495: if (is_integer(t1) && is_integer(t2) &&
1.24 rillig 496: !arg1->t_isenum && !arg2->t_isenum) {
1.1 cgd 497: if (promote) {
498: /*
1.32 rillig 499: * XXX Here is a problem: Although it is possible to
1.1 cgd 500: * pass an int where a char/short it expected, there
501: * may be loss in significant digits. We should first
502: * check for const arguments if they can be converted
503: * into the original parameter type.
504: */
505: if (t1 == FLOAT) {
506: t1 = DOUBLE;
507: } else if (t1 == CHAR || t1 == SCHAR) {
508: t1 = INT;
509: } else if (t1 == UCHAR) {
510: t1 = tflag ? UINT : INT;
511: } else if (t1 == SHORT) {
512: t1 = INT;
513: } else if (t1 == USHORT) {
514: /* CONSTCOND */
515: t1 = INT_MAX < USHRT_MAX || tflag ? UINT : INT;
516: }
517: }
518:
1.30 rillig 519: if (signed_type(t1) == signed_type(t2)) {
1.1 cgd 520:
521: /*
522: * types differ only in signedness; get information
523: * about arguments
524: */
525:
526: /*
527: * treat a definition like a call with variable
528: * arguments
529: */
530: ai1 = call1 != NULL ? call1->f_args : NULL;
531:
532: /*
533: * if two calls are compared, ai1 is set to the
534: * information for the n-th argument, if this was
535: * a constant, otherwise to NULL
536: */
1.29 rillig 537: for ( ; ai1 != NULL; ai1 = ai1->a_next) {
1.1 cgd 538: if (ai1->a_num == n)
539: break;
540: }
541: /*
542: * ai is set to the information of the n-th arg
543: * of the (second) call, if this was a constant,
544: * otherwise to NULL
545: */
1.29 rillig 546: for (ai = call->f_args; ai != NULL; ai = ai->a_next) {
1.1 cgd 547: if (ai->a_num == n)
548: break;
549: }
550:
551: if (ai1 == NULL && ai == NULL) {
552: /* no constant at all */
553: if (!hflag)
554: return;
555: } else if (ai1 == NULL || ai == NULL) {
556: /* one constant */
557: if (ai == NULL)
558: ai = ai1;
559: if (ai->a_zero || ai->a_pcon)
560: /* same value in signed and unsigned */
561: return;
562: /* value (not representation) differently */
563: } else {
564: /*
565: * two constants, one signed, one unsigned;
566: * if the msb of one of the constants is set,
567: * the argument is used inconsistently.
568: */
569: if (!ai1->a_ncon && !ai->a_ncon)
570: return;
571: }
572: }
573:
1.33 ! rillig 574: } else if (t1 == PTR && is_integer(t2)) {
1.29 rillig 575: for (ai = call->f_args; ai != NULL; ai = ai->a_next) {
1.1 cgd 576: if (ai->a_num == n)
577: break;
578: }
1.3 cgd 579: /*
580: * Vendor implementations of lint (e.g. HP-UX, Digital UNIX)
581: * don't care about the size of the integer argument,
582: * only whether or not it is zero. We do the same.
583: */
1.1 cgd 584: if (ai != NULL && ai->a_zero)
585: return;
586: }
587:
588: pos1 = xstrdup(mkpos(pos1p));
1.18 christos 589: /* %s, arg %d used inconsistently\t%s[%s] :: %s[%s] */
1.31 rillig 590: msg(6, hte->h_name, n, pos1, type_name(arg1),
591: mkpos(&call->f_pos), type_name(arg2));
1.1 cgd 592: free(pos1);
593: }
594:
595: /*
596: * Compare the types in the NULL-terminated array ap with the format
597: * string fmt.
598: */
599: static void
1.10 lukem 600: printflike(hte_t *hte, fcall_t *call, int n, const char *fmt, type_t **ap)
1.1 cgd 601: {
602: const char *fp;
603: int fc;
604: int fwidth, prec, left, sign, space, alt, zero;
1.6 mycroft 605: tspec_t sz, t1, t2 = NOTSPEC;
1.1 cgd 606: type_t *tp;
607:
608: fp = fmt;
609: fc = *fp++;
610:
611: for ( ; ; ) {
612: if (fc == '\0') {
613: if (*ap != NULL)
614: tomanyarg(hte, call);
615: break;
616: }
617: if (fc != '%') {
618: badfmt(hte, call);
619: break;
620: }
621: fc = *fp++;
622: fwidth = prec = left = sign = space = alt = zero = 0;
623: sz = NOTSPEC;
624:
625: /* Flags */
626: for ( ; ; ) {
627: if (fc == '-') {
628: if (left)
629: break;
630: left = 1;
631: } else if (fc == '+') {
632: if (sign)
633: break;
634: sign = 1;
635: } else if (fc == ' ') {
636: if (space)
637: break;
638: space = 1;
639: } else if (fc == '#') {
640: if (alt)
641: break;
642: alt = 1;
643: } else if (fc == '0') {
644: if (zero)
645: break;
646: zero = 1;
647: } else {
648: break;
649: }
650: fc = *fp++;
651: }
652:
653: /* field width */
654: if (isdigit(fc)) {
655: fwidth = 1;
656: do { fc = *fp++; } while (isdigit(fc)) ;
657: } else if (fc == '*') {
658: fwidth = 1;
659: fc = *fp++;
660: if ((tp = *ap++) == NULL) {
661: tofewarg(hte, call);
662: break;
663: }
664: n++;
665: if ((t1 = tp->t_tspec) != INT && (hflag || t1 != UINT))
666: inconarg(hte, call, n);
667: }
668:
669: /* precision */
670: if (fc == '.') {
671: fc = *fp++;
672: prec = 1;
673: if (isdigit(fc)) {
674: do { fc = *fp++; } while (isdigit(fc));
675: } else if (fc == '*') {
676: fc = *fp++;
677: if ((tp = *ap++) == NULL) {
678: tofewarg(hte, call);
679: break;
680: }
681: n++;
682: if (tp->t_tspec != INT)
683: inconarg(hte, call, n);
684: } else {
685: badfmt(hte, call);
686: break;
687: }
688: }
689:
690: if (fc == 'h') {
691: sz = SHORT;
692: } else if (fc == 'l') {
693: sz = LONG;
694: } else if (fc == 'q') {
695: sz = QUAD;
696: } else if (fc == 'L') {
697: sz = LDOUBLE;
698: }
699: if (sz != NOTSPEC)
700: fc = *fp++;
701:
702: if (fc == '%') {
703: if (sz != NOTSPEC || left || sign || space ||
704: alt || zero || prec || fwidth) {
705: badfmt(hte, call);
706: }
707: fc = *fp++;
708: continue;
709: }
710:
711: if (fc == '\0') {
712: badfmt(hte, call);
713: break;
714: }
715:
716: if ((tp = *ap++) == NULL) {
717: tofewarg(hte, call);
718: break;
719: }
720: n++;
721: if ((t1 = tp->t_tspec) == PTR)
722: t2 = tp->t_subt->t_tspec;
723:
724: if (fc == 'd' || fc == 'i') {
725: if (alt || sz == LDOUBLE) {
726: badfmt(hte, call);
727: break;
728: }
729: int_conv:
730: if (sz == LONG) {
731: if (t1 != LONG && (hflag || t1 != ULONG))
732: inconarg(hte, call, n);
733: } else if (sz == QUAD) {
734: if (t1 != QUAD && (hflag || t1 != UQUAD))
735: inconarg(hte, call, n);
736: } else {
737: /*
738: * SHORT is always promoted to INT, USHORT
739: * to INT or UINT.
740: */
741: if (t1 != INT && (hflag || t1 != UINT))
742: inconarg(hte, call, n);
743: }
744: } else if (fc == 'o' || fc == 'u' || fc == 'x' || fc == 'X') {
745: if ((alt && fc == 'u') || sz == LDOUBLE)
746: badfmt(hte, call);
747: uint_conv:
748: if (sz == LONG) {
749: if (t1 != ULONG && (hflag || t1 != LONG))
750: inconarg(hte, call, n);
751: } else if (sz == QUAD) {
752: if (t1 != UQUAD && (hflag || t1 != QUAD))
753: inconarg(hte, call, n);
754: } else if (sz == SHORT) {
755: /* USHORT was promoted to INT or UINT */
756: if (t1 != UINT && t1 != INT)
757: inconarg(hte, call, n);
758: } else {
759: if (t1 != UINT && (hflag || t1 != INT))
760: inconarg(hte, call, n);
761: }
762: } else if (fc == 'D' || fc == 'O' || fc == 'U') {
763: if ((alt && fc != 'O') || sz != NOTSPEC || !tflag)
764: badfmt(hte, call);
765: sz = LONG;
766: if (fc == 'D') {
767: goto int_conv;
768: } else {
769: goto uint_conv;
770: }
771: } else if (fc == 'f' || fc == 'e' || fc == 'E' ||
772: fc == 'g' || fc == 'G') {
773: if (sz == NOTSPEC)
774: sz = DOUBLE;
775: if (sz != DOUBLE && sz != LDOUBLE)
776: badfmt(hte, call);
777: if (t1 != sz)
778: inconarg(hte, call, n);
779: } else if (fc == 'c') {
780: if (sz != NOTSPEC || alt || zero)
781: badfmt(hte, call);
782: if (t1 != INT)
783: inconarg(hte, call, n);
784: } else if (fc == 's') {
785: if (sz != NOTSPEC || alt || zero)
786: badfmt(hte, call);
787: if (t1 != PTR ||
788: (t2 != CHAR && t2 != UCHAR && t2 != SCHAR)) {
789: inconarg(hte, call, n);
790: }
791: } else if (fc == 'p') {
792: if (fwidth || prec || sz != NOTSPEC || alt || zero)
793: badfmt(hte, call);
794: if (t1 != PTR || (hflag && t2 != VOID))
795: inconarg(hte, call, n);
796: } else if (fc == 'n') {
797: if (fwidth || prec || alt || zero || sz == LDOUBLE)
798: badfmt(hte, call);
799: if (t1 != PTR) {
800: inconarg(hte, call, n);
801: } else if (sz == LONG) {
802: if (t2 != LONG && t2 != ULONG)
803: inconarg(hte, call, n);
804: } else if (sz == SHORT) {
805: if (t2 != SHORT && t2 != USHORT)
806: inconarg(hte, call, n);
807: } else {
808: if (t2 != INT && t2 != UINT)
809: inconarg(hte, call, n);
810: }
811: } else {
812: badfmt(hte, call);
813: break;
814: }
815:
816: fc = *fp++;
817: }
818: }
819:
820: /*
821: * Compare the types in the NULL-terminated array ap with the format
822: * string fmt.
823: */
824: static void
1.10 lukem 825: scanflike(hte_t *hte, fcall_t *call, int n, const char *fmt, type_t **ap)
1.1 cgd 826: {
827: const char *fp;
828: int fc;
829: int noasgn, fwidth;
1.6 mycroft 830: tspec_t sz, t1 = NOTSPEC, t2 = NOTSPEC;
1.5 christos 831: type_t *tp = NULL;
1.1 cgd 832:
833: fp = fmt;
834: fc = *fp++;
835:
836: for ( ; ; ) {
837: if (fc == '\0') {
838: if (*ap != NULL)
839: tomanyarg(hte, call);
840: break;
841: }
842: if (fc != '%') {
843: badfmt(hte, call);
844: break;
845: }
846: fc = *fp++;
847:
848: noasgn = fwidth = 0;
849: sz = NOTSPEC;
850:
851: if (fc == '*') {
852: noasgn = 1;
853: fc = *fp++;
854: }
1.10 lukem 855:
1.1 cgd 856: if (isdigit(fc)) {
857: fwidth = 1;
858: do { fc = *fp++; } while (isdigit(fc));
859: }
860:
861: if (fc == 'h') {
862: sz = SHORT;
863: } else if (fc == 'l') {
864: sz = LONG;
865: } else if (fc == 'q') {
866: sz = QUAD;
867: } else if (fc == 'L') {
868: sz = LDOUBLE;
869: }
870: if (sz != NOTSPEC)
871: fc = *fp++;
872:
873: if (fc == '%') {
874: if (sz != NOTSPEC || noasgn || fwidth)
875: badfmt(hte, call);
876: fc = *fp++;
877: continue;
878: }
879:
880: if (!noasgn) {
881: if ((tp = *ap++) == NULL) {
882: tofewarg(hte, call);
883: break;
884: }
885: n++;
886: if ((t1 = tp->t_tspec) == PTR)
887: t2 = tp->t_subt->t_tspec;
888: }
889:
890: if (fc == 'd' || fc == 'i' || fc == 'n') {
891: if (sz == LDOUBLE)
892: badfmt(hte, call);
893: if (sz != SHORT && sz != LONG && sz != QUAD)
894: sz = INT;
895: conv:
896: if (!noasgn) {
897: if (t1 != PTR) {
898: inconarg(hte, call, n);
1.30 rillig 899: } else if (t2 != signed_type(sz)) {
1.1 cgd 900: inconarg(hte, call, n);
901: } else if (hflag && t2 != sz) {
902: inconarg(hte, call, n);
903: } else if (tp->t_subt->t_const) {
904: inconarg(hte, call, n);
905: }
906: }
907: } else if (fc == 'o' || fc == 'u' || fc == 'x') {
908: if (sz == LDOUBLE)
909: badfmt(hte, call);
910: if (sz == SHORT) {
911: sz = USHORT;
912: } else if (sz == LONG) {
913: sz = ULONG;
914: } else if (sz == QUAD) {
915: sz = UQUAD;
916: } else {
917: sz = UINT;
918: }
919: goto conv;
920: } else if (fc == 'D') {
921: if (sz != NOTSPEC || !tflag)
922: badfmt(hte, call);
923: sz = LONG;
924: goto conv;
925: } else if (fc == 'O') {
926: if (sz != NOTSPEC || !tflag)
927: badfmt(hte, call);
928: sz = ULONG;
929: goto conv;
930: } else if (fc == 'X') {
931: /*
932: * XXX valid in ANSI C, but in NetBSD's libc imple-
1.32 rillig 933: * mented as "lx". That's why it should be avoided.
1.1 cgd 934: */
935: if (sz != NOTSPEC || !tflag)
936: badfmt(hte, call);
937: sz = ULONG;
938: goto conv;
939: } else if (fc == 'E') {
940: /*
941: * XXX valid in ANSI C, but in NetBSD's libc imple-
1.32 rillig 942: * mented as "lf". That's why it should be avoided.
1.1 cgd 943: */
944: if (sz != NOTSPEC || !tflag)
945: badfmt(hte, call);
946: sz = DOUBLE;
947: goto conv;
948: } else if (fc == 'F') {
949: /* XXX only for backward compatibility */
950: if (sz != NOTSPEC || !tflag)
951: badfmt(hte, call);
952: sz = DOUBLE;
953: goto conv;
954: } else if (fc == 'G') {
955: /*
956: * XXX valid in ANSI C, but in NetBSD's libc not
957: * implemented
958: */
959: if (sz != NOTSPEC && sz != LONG && sz != LDOUBLE)
960: badfmt(hte, call);
961: goto fconv;
962: } else if (fc == 'e' || fc == 'f' || fc == 'g') {
963: fconv:
964: if (sz == NOTSPEC) {
965: sz = FLOAT;
966: } else if (sz == LONG) {
967: sz = DOUBLE;
968: } else if (sz != LDOUBLE) {
969: badfmt(hte, call);
970: sz = FLOAT;
971: }
972: goto conv;
973: } else if (fc == 's' || fc == '[' || fc == 'c') {
974: if (sz != NOTSPEC)
975: badfmt(hte, call);
976: if (fc == '[') {
977: if ((fc = *fp++) == '-') {
978: badfmt(hte, call);
979: fc = *fp++;
980: }
981: if (fc != ']') {
982: badfmt(hte, call);
983: if (fc == '\0')
984: break;
985: }
986: }
987: if (!noasgn) {
988: if (t1 != PTR) {
989: inconarg(hte, call, n);
990: } else if (t2 != CHAR && t2 != UCHAR &&
991: t2 != SCHAR) {
992: inconarg(hte, call, n);
993: }
994: }
995: } else if (fc == 'p') {
996: if (sz != NOTSPEC)
997: badfmt(hte, call);
998: if (!noasgn) {
999: if (t1 != PTR || t2 != PTR) {
1000: inconarg(hte, call, n);
1001: } else if (tp->t_subt->t_subt->t_tspec!=VOID) {
1002: if (hflag)
1003: inconarg(hte, call, n);
1004: }
1005: }
1006: } else {
1007: badfmt(hte, call);
1008: break;
1009: }
1010:
1011: fc = *fp++;
1012: }
1013: }
1014:
1015: static void
1.10 lukem 1016: badfmt(hte_t *hte, fcall_t *call)
1.1 cgd 1017: {
1.10 lukem 1018:
1.1 cgd 1019: /* %s: malformed format string\t%s */
1020: msg(13, hte->h_name, mkpos(&call->f_pos));
1021: }
1022:
1023: static void
1.10 lukem 1024: inconarg(hte_t *hte, fcall_t *call, int n)
1.1 cgd 1025: {
1.10 lukem 1026:
1.1 cgd 1027: /* %s, arg %d inconsistent with format\t%s(%d) */
1028: msg(14, hte->h_name, n, mkpos(&call->f_pos));
1029: }
1030:
1031: static void
1.10 lukem 1032: tofewarg(hte_t *hte, fcall_t *call)
1.1 cgd 1033: {
1.10 lukem 1034:
1.1 cgd 1035: /* %s: too few args for format \t%s */
1036: msg(15, hte->h_name, mkpos(&call->f_pos));
1037: }
1038:
1039: static void
1.10 lukem 1040: tomanyarg(hte_t *hte, fcall_t *call)
1.1 cgd 1041: {
1.10 lukem 1042:
1.1 cgd 1043: /* %s: too many args for format \t%s */
1044: msg(16, hte->h_name, mkpos(&call->f_pos));
1045: }
1046:
1.21 christos 1047: /*
1048: * List of functions where we usually don't care about their result.
1049: * NB: Must be sorted.
1050: */
1051: static const char ignorelist[][8] = {
1052: "memcpy",
1053: "memmove",
1054: "memset",
1055: "printf",
1056: "strcat",
1057: "strcpy",
1058: "vprintf",
1059: };
1.1 cgd 1060:
1061: /*
1062: * Print warnings for return values which are used, but not returned,
1063: * or return values which are always or sometimes ignored.
1064: */
1065: static void
1.10 lukem 1066: chkrvu(hte_t *hte, sym_t *def)
1.1 cgd 1067: {
1068: fcall_t *call;
1069: int used, ignored;
1070:
1071: if (def == NULL)
1.22 mbalmer 1072: /* don't know whether or not the functions returns a value */
1.1 cgd 1073: return;
1074:
1075: if (hte->h_calls == NULL)
1076: return;
1077:
1078: if (def->s_rval) {
1.21 christos 1079: /*
1080: * XXX as soon as we are able to disable single warnings
1081: * the following dependencies from hflag should be removed.
1.32 rillig 1082: * but for now I don't want to be bothered by this warnings
1.21 christos 1083: * which are almost always useless.
1084: */
1085: if (hflag == 0)
1086: return;
1087: if (hflag == 1 && bsearch(hte->h_name, ignorelist,
1088: __arraycount(ignorelist), sizeof(ignorelist[0]),
1089: (int (*)(const void *, const void *))strcmp) != NULL)
1090: return;
1091:
1.1 cgd 1092: /* function has return value */
1093: used = ignored = 0;
1.29 rillig 1094: for (call = hte->h_calls; call != NULL; call = call->f_next) {
1.8 mycroft 1095: used |= call->f_rused || call->f_rdisc;
1.1 cgd 1096: ignored |= !call->f_rused && !call->f_rdisc;
1097: }
1098: if (!used && ignored) {
1.21 christos 1099: /* %s returns value which is always ignored */
1100: msg(8, hte->h_name);
1.1 cgd 1101: } else if (used && ignored) {
1.21 christos 1102: /* %s returns value which is sometimes ign. */
1103: msg(9, hte->h_name);
1.1 cgd 1104: }
1105: } else {
1106: /* function has no return value */
1.29 rillig 1107: for (call = hte->h_calls; call != NULL; call = call->f_next) {
1.1 cgd 1108: if (call->f_rused)
1109: /* %s value is used( %s ), but none ret. */
1110: msg(10, hte->h_name, mkpos(&call->f_pos));
1111: }
1112: }
1113: }
1114:
1115: /*
1116: * Print warnings for inconsistent argument declarations.
1117: */
1118: static void
1.10 lukem 1119: chkadecl(hte_t *hte, sym_t *def, sym_t *decl)
1.1 cgd 1120: {
1.20 lukem 1121: int osdef, eq, dowarn, n;
1.1 cgd 1122: sym_t *sym1, *sym;
1123: type_t **ap1, **ap2, *tp1, *tp2;
1124: char *pos1;
1125: const char *pos2;
1126:
1127: osdef = 0;
1128: if (def != NULL) {
1129: osdef = def->s_osdef;
1130: sym1 = def;
1131: } else if (decl != NULL && TP(decl->s_type)->t_proto) {
1132: sym1 = decl;
1133: } else {
1134: return;
1135: }
1136: if (TP(sym1->s_type)->t_tspec != FUNC)
1137: return;
1138:
1139: /*
1140: * XXX Prototypes should also be compared with old style function
1141: * declarations.
1142: */
1143:
1.28 rillig 1144: for (sym = hte->h_syms; sym != NULL; sym = sym->s_next) {
1.1 cgd 1145: if (sym == sym1 || !TP(sym->s_type)->t_proto)
1146: continue;
1147: ap1 = TP(sym1->s_type)->t_args;
1148: ap2 = TP(sym->s_type)->t_args;
1149: n = 0;
1150: while (*ap1 != NULL && *ap2 != NULL) {
1.19 christos 1151: type_t *xt1, *xt2;
1.20 lukem 1152: dowarn = 0;
1153: eq = eqtype(xt1 = *ap1, xt2 = *ap2, 1, osdef, 0, &dowarn);
1154: if (!eq || dowarn) {
1.1 cgd 1155: pos1 = xstrdup(mkpos(&sym1->s_pos));
1156: pos2 = mkpos(&sym->s_pos);
1157: /* %s, arg %d declared inconsistently ... */
1.19 christos 1158: msg(11, hte->h_name, n + 1,
1.31 rillig 1159: type_name(xt1), type_name(xt2), pos1, pos2);
1.1 cgd 1160: free(pos1);
1161: }
1162: n++;
1163: ap1++;
1164: ap2++;
1165: }
1166: if (*ap1 == *ap2) {
1167: tp1 = TP(sym1->s_type);
1168: tp2 = TP(sym->s_type);
1169: if (tp1->t_vararg == tp2->t_vararg)
1170: continue;
1171: if (tp2->t_vararg &&
1172: sym1->s_va && sym1->s_nva == n && !sflag) {
1173: continue;
1174: }
1175: }
1176: /* %s: variable # of args declared\t%s :: %s */
1177: pos1 = xstrdup(mkpos(&sym1->s_pos));
1178: msg(12, hte->h_name, pos1, mkpos(&sym->s_pos));
1179: free(pos1);
1180: }
1181: }
1182:
1183:
1184: /*
1185: * Check compatibility of two types. Returns 1 if types are compatible,
1186: * otherwise 0.
1187: *
1188: * ignqual if set, ignore qualifiers of outhermost type; used for
1189: * function arguments
1.7 mycroft 1190: * promote if set, promote left type before comparison; used for
1191: * comparisons of arguments with parameters of old style
1.1 cgd 1192: * definitions
1193: * asgn left indirected type must have at least the same qualifiers
1194: * like right indirected type (for assignments and function
1195: * arguments)
1.20 lukem 1196: * *dowarn set to 1 if an old style declaration was compared with
1.1 cgd 1197: * an incompatible prototype declaration
1198: */
1199: static int
1.20 lukem 1200: eqtype(type_t *tp1, type_t *tp2, int ignqual, int promot, int asgn, int *dowarn)
1.1 cgd 1201: {
1202: tspec_t t, to;
1203: int indir;
1204:
1205: to = NOTSPEC;
1206: indir = 0;
1207:
1208: while (tp1 != NULL && tp2 != NULL) {
1209:
1210: t = tp1->t_tspec;
1211: if (promot) {
1212: if (t == FLOAT) {
1213: t = DOUBLE;
1214: } else if (t == CHAR || t == SCHAR) {
1215: t = INT;
1216: } else if (t == UCHAR) {
1217: t = tflag ? UINT : INT;
1218: } else if (t == SHORT) {
1219: t = INT;
1220: } else if (t == USHORT) {
1221: /* CONSTCOND */
1222: t = INT_MAX < USHRT_MAX || tflag ? UINT : INT;
1223: }
1224: }
1225:
1226: if (asgn && to == PTR) {
1227: if (indir == 1 && (t == VOID || tp2->t_tspec == VOID))
1.27 rillig 1228: return 1;
1.1 cgd 1229: }
1.10 lukem 1230:
1.1 cgd 1231: if (t != tp2->t_tspec) {
1232: /*
1233: * Give pointer to types which differ only in
1234: * signedness a chance if not sflag and not hflag.
1235: */
1236: if (sflag || hflag || to != PTR)
1.27 rillig 1237: return 0;
1.30 rillig 1238: if (signed_type(t) != signed_type(tp2->t_tspec))
1.27 rillig 1239: return 0;
1.1 cgd 1240: }
1241:
1242: if (tp1->t_isenum && tp2->t_isenum) {
1243: if (tp1->t_istag && tp2->t_istag) {
1.27 rillig 1244: return tp1->t_tag == tp2->t_tag;
1.1 cgd 1245: } else if (tp1->t_istynam && tp2->t_istynam) {
1.27 rillig 1246: return tp1->t_tynam == tp2->t_tynam;
1.3 cgd 1247: } else if (tp1->t_isuniqpos && tp2->t_isuniqpos) {
1248: return (tp1->t_uniqpos.p_line ==
1249: tp2->t_uniqpos.p_line &&
1250: tp1->t_uniqpos.p_file ==
1251: tp2->t_uniqpos.p_file &&
1252: tp1->t_uniqpos.p_uniq ==
1253: tp2->t_uniqpos.p_uniq);
1.1 cgd 1254: } else {
1.27 rillig 1255: return 0;
1.1 cgd 1256: }
1257: }
1258:
1259: /*
1260: * XXX Handle combinations of enum and int if eflag is set.
1261: * But note: enum and 0 should be allowed.
1262: */
1263:
1264: if (asgn && indir == 1) {
1265: if (!tp1->t_const && tp2->t_const)
1.27 rillig 1266: return 0;
1.1 cgd 1267: if (!tp1->t_volatile && tp2->t_volatile)
1.27 rillig 1268: return 0;
1.1 cgd 1269: } else if (!ignqual && !tflag) {
1270: if (tp1->t_const != tp2->t_const)
1.27 rillig 1271: return 0;
1.1 cgd 1272: if (tp1->t_const != tp2->t_const)
1.27 rillig 1273: return 0;
1.1 cgd 1274: }
1275:
1276: if (t == STRUCT || t == UNION) {
1277: if (tp1->t_istag && tp2->t_istag) {
1.27 rillig 1278: return tp1->t_tag == tp2->t_tag;
1.1 cgd 1279: } else if (tp1->t_istynam && tp2->t_istynam) {
1.27 rillig 1280: return tp1->t_tynam == tp2->t_tynam;
1.3 cgd 1281: } else if (tp1->t_isuniqpos && tp2->t_isuniqpos) {
1282: return (tp1->t_uniqpos.p_line ==
1283: tp2->t_uniqpos.p_line &&
1284: tp1->t_uniqpos.p_file ==
1285: tp2->t_uniqpos.p_file &&
1286: tp1->t_uniqpos.p_uniq ==
1287: tp2->t_uniqpos.p_uniq);
1.1 cgd 1288: } else {
1.27 rillig 1289: return 0;
1.1 cgd 1290: }
1291: }
1292:
1293: if (t == ARRAY && tp1->t_dim != tp2->t_dim) {
1294: if (tp1->t_dim != 0 && tp2->t_dim != 0)
1.27 rillig 1295: return 0;
1.1 cgd 1296: }
1297:
1298: if (t == FUNC) {
1299: if (tp1->t_proto && tp2->t_proto) {
1.20 lukem 1300: if (!eqargs(tp1, tp2, dowarn))
1.27 rillig 1301: return 0;
1.1 cgd 1302: } else if (tp1->t_proto) {
1.20 lukem 1303: if (!mnoarg(tp1, dowarn))
1.27 rillig 1304: return 0;
1.1 cgd 1305: } else if (tp2->t_proto) {
1.20 lukem 1306: if (!mnoarg(tp2, dowarn))
1.27 rillig 1307: return 0;
1.1 cgd 1308: }
1309: }
1310:
1311: tp1 = tp1->t_subt;
1312: tp2 = tp2->t_subt;
1313: ignqual = promot = 0;
1314: to = t;
1315: indir++;
1316:
1317: }
1318:
1.27 rillig 1319: return tp1 == tp2;
1.1 cgd 1320: }
1321:
1322: /*
1323: * Compares arguments of two prototypes
1324: */
1325: static int
1.20 lukem 1326: eqargs(type_t *tp1, type_t *tp2, int *dowarn)
1.1 cgd 1327: {
1328: type_t **a1, **a2;
1329:
1330: if (tp1->t_vararg != tp2->t_vararg)
1.27 rillig 1331: return 0;
1.1 cgd 1332:
1333: a1 = tp1->t_args;
1334: a2 = tp2->t_args;
1335:
1336: while (*a1 != NULL && *a2 != NULL) {
1337:
1.20 lukem 1338: if (eqtype(*a1, *a2, 1, 0, 0, dowarn) == 0)
1.27 rillig 1339: return 0;
1.1 cgd 1340:
1341: a1++;
1342: a2++;
1343:
1344: }
1345:
1.27 rillig 1346: return *a1 == *a2;
1.1 cgd 1347: }
1348:
1349: /*
1350: * mnoarg() (matches functions with no argument type information)
1351: * returns 1 if all parameters of a prototype are compatible with
1352: * and old style function declaration.
1353: * This is the case if following conditions are met:
1354: * 1. the prototype must have a fixed number of parameters
1355: * 2. no parameter is of type float
1356: * 3. no parameter is converted to another type if integer promotion
1357: * is applied on it
1358: */
1359: static int
1.20 lukem 1360: mnoarg(type_t *tp, int *dowarn)
1.1 cgd 1361: {
1362: type_t **arg;
1363: tspec_t t;
1364:
1.20 lukem 1365: if (tp->t_vararg && dowarn != NULL)
1366: *dowarn = 1;
1.1 cgd 1367: for (arg = tp->t_args; *arg != NULL; arg++) {
1368: if ((t = (*arg)->t_tspec) == FLOAT)
1.27 rillig 1369: return 0;
1.1 cgd 1370: if (t == CHAR || t == SCHAR || t == UCHAR)
1.27 rillig 1371: return 0;
1.1 cgd 1372: if (t == SHORT || t == USHORT)
1.27 rillig 1373: return 0;
1.1 cgd 1374: }
1.27 rillig 1375: return 1;
1.1 cgd 1376: }
CVSweb <webmaster@jp.NetBSD.org>