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