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