xref: /netbsd-src/tests/usr.bin/xlint/lint1/queries.c (revision 32d1c65c71fbdb65a012e8392a62a757dd6853e9)
1 /*	$NetBSD: queries.c,v 1.30 2024/11/23 00:01:48 rillig Exp $	*/
2 # 3 "queries.c"
3 
4 /*
5  * Demonstrate the case-by-case queries.  Unlike warnings, queries do not
6  * point to questionable code but rather to code that may be interesting to
7  * inspect manually on a case-by-case basis.
8  *
9  * Possible use cases are:
10  *
11  *	Understanding how C works internally, by making the usual arithmetic
12  *	conversions visible.
13  *
14  *	Finding code that intentionally suppresses a regular lint warning,
15  *	such as casts between arithmetic types.
16  */
17 
18 /* lint1-extra-flags: -q 1,2,3,4,5,6,7,8,9,10 */
19 /* lint1-extra-flags: -q 11,12,13,14,15,16,17,18,19,20 */
20 /* lint1-extra-flags: -X 351 */
21 
22 typedef unsigned char u8_t;
23 typedef unsigned short u16_t;
24 typedef unsigned int u32_t;
25 typedef unsigned long long u64_t;
26 typedef signed char s8_t;
27 typedef signed short s16_t;
28 typedef signed int s32_t;
29 typedef signed long long s64_t;
30 
31 typedef float f32_t;
32 typedef double f64_t;
33 typedef float _Complex c32_t;
34 typedef double _Complex c64_t;
35 
36 typedef char *str_t;
37 typedef const char *cstr_t;
38 typedef volatile char *vstr_t;
39 typedef typeof(sizeof 0) size_t;
40 
41 _Bool cond;
42 
43 u8_t u8;
44 u16_t u16;
45 u32_t u32;
46 u64_t u64;
47 
48 s8_t s8;
49 s16_t s16;
50 s32_t s32;
51 s64_t s64;
52 
53 struct {
54 	unsigned u8:8;
55 	unsigned u9:9;
56 	unsigned u10:10;
57 	unsigned u32:32;
58 	int s8:8;
59 	int s9:9;
60 	int s10:10;
61 	int s32:32;
62 } bits;
63 
64 f32_t f32;
65 f64_t f64;
66 
67 c32_t c32;
68 c64_t c64;
69 
70 char *str;
71 const char *cstr;
72 volatile char *vstr;
73 const volatile char *cvstr;
74 
75 void *void_ptr;
76 const void *const_void_ptr;
77 char *char_ptr;
78 int *int_ptr;
79 
80 int
81 Q1(double dbl)
82 {
83 	/* expect+1: implicit conversion from floating point 'double' to integer 'int' [Q1] */
84 	return dbl;
85 }
86 
87 int
88 Q2(double dbl)
89 {
90 	/* expect+1: cast from floating point 'double' to integer 'int' [Q2] */
91 	return (int)dbl;
92 }
93 
94 // The Q3 query triggers so often that it also occurs outside this function.
95 void
96 Q3(int i, unsigned u)
97 {
98 	/* expect+1: implicit conversion changes sign from 'int' to 'unsigned int' [Q3] */
99 	u = i;
100 
101 	/* expect+1: implicit conversion changes sign from 'unsigned int' to 'int' [Q3] */
102 	i = u;
103 
104 	/* expect+2: implicit conversion changes sign from 'unsigned char' to 'int' [Q3] */
105 	/* expect+1: implicit conversion changes sign from 'int' to 'unsigned short' [Q3] */
106 	u16 += u8;
107 	/* expect+2: implicit conversion changes sign from 'unsigned short' to 'int' [Q3] */
108 	/* expect+1: implicit conversion changes sign from 'int' to 'unsigned int' [Q3] */
109 	u32 += u16;
110 }
111 
112 unsigned long long
113 Q4(signed char *ptr, int i, unsigned long long ull, size_t sz)
114 {
115 
116 	/*
117 	 * For constants, the usual arithmetic conversions are usually not
118 	 * interesting, so omit them.
119 	 */
120 	u32 = u32 & 0xff;
121 	u32 &= 0xff;
122 
123 	/* expect+2: usual arithmetic conversion for '&' from 'int' to 'unsigned int' [Q4] */
124 	/* expect+1: implicit conversion changes sign from 'int' to 'unsigned int' [Q3] */
125 	u32 = u32 & s32;
126 	/*
127 	 * XXX: C99 5.6.16.2 says that the usual arithmetic conversions
128 	 * happen for compound assignments as well.
129 	 */
130 	/* expect+1: implicit conversion changes sign from 'int' to 'unsigned int' [Q3] */
131 	u32 &= s32;
132 
133 	/* expect+3: implicit conversion changes sign from 'unsigned char' to 'int' [Q3] */
134 	/* expect+2: usual arithmetic conversion for '&' from 'int' to 'unsigned int' [Q4] */
135 	/* expect+1: implicit conversion changes sign from 'int' to 'unsigned int' [Q3] */
136 	u32 = u32 & u8;
137 
138 	s8 = ptr[sz];
139 
140 	/*
141 	 * The conversion from 'signed char' to 'int' is done by the integer
142 	 * promotions (C11 6.3.1.1p2), not by the usual arithmetic
143 	 * conversions (C11 6.3.1.8p1).
144 	 */
145 	/* expect+2: usual arithmetic conversion for '+' from 'int' to 'unsigned long long' [Q4] */
146 	/* expect+1: implicit conversion changes sign from 'int' to 'unsigned long long' [Q3] */
147 	return ptr[0] + ptr[1] + i + ull;
148 }
149 
150 void
151 Q5(signed char *ptr, int i)
152 {
153 	if (ptr + i > ptr)
154 		return;
155 
156 	/* expect+1: pointer addition has integer on the left-hand side [Q5] */
157 	if (i + ptr > ptr)
158 		return;
159 
160 	if (ptr[i] != '\0')
161 		return;
162 
163 	/* expect+1: pointer addition has integer on the left-hand side [Q5] */
164 	if (i[ptr] != '\0')
165 		return;
166 }
167 
168 void
169 Q6(int i)
170 {
171 	/* expect+1: no-op cast from 'int' to 'int' [Q6] */
172 	i = (int)4;
173 
174 	/* expect+1: no-op cast from 'int' to 'int' [Q6] */
175 	i = (int)i + 1;
176 }
177 
178 void *allocate(void);
179 
180 void
181 Q7(void)
182 {
183 
184 	/* expect+2: no-op cast from '_Bool' to '_Bool' [Q6] */
185 	/* expect+1: redundant cast from '_Bool' to '_Bool' before assignment [Q7] */
186 	cond = (_Bool)cond;
187 	cond = (_Bool)u8;
188 	u8 = (u8_t)cond;
189 
190 	/* expect+2: no-op cast from 'unsigned char' to 'unsigned char' [Q6] */
191 	/* expect+1: redundant cast from 'unsigned char' to 'unsigned char' before assignment [Q7] */
192 	u8 = (u8_t)u8;
193 	u8 = (u8_t)u16;
194 	u8 = (u16_t)u8;
195 	/* expect+1: no-op cast from 'unsigned short' to 'unsigned short' [Q6] */
196 	u8 = (u16_t)u16;
197 	/* expect+1: no-op cast from 'unsigned char' to 'unsigned char' [Q6] */
198 	u16 = (u8_t)u8;
199 	u16 = (u8_t)u16;
200 	/* expect+1: redundant cast from 'unsigned char' to 'unsigned short' before assignment [Q7] */
201 	u16 = (u16_t)u8;
202 	/* expect+2: no-op cast from 'unsigned short' to 'unsigned short' [Q6] */
203 	/* expect+1: redundant cast from 'unsigned short' to 'unsigned short' before assignment [Q7] */
204 	u16 = (u16_t)u16;
205 
206 	/* Mixing signed and unsigned types. */
207 	u8 = (u8_t)s8;
208 	s8 = (s8_t)u8;
209 	/* expect+1: redundant cast from 'unsigned char' to 'short' before assignment [Q7] */
210 	s16 = (s16_t)u8;
211 	/* expect+1: redundant cast from 'signed char' to 'short' before assignment [Q7] */
212 	s16 = (s16_t)s8;
213 
214 
215 	/*
216 	 * Neither GCC nor Clang accept typeof(bit-field), as that would add
217 	 * unnecessary complexity.  Lint accepts it but silently discards the
218 	 * bit-field portion from the type; see dcs_add_type.
219 	 */
220 	/* expect+1: redundant cast from 'unsigned char' to 'unsigned int' before assignment [Q7] */
221 	bits.u9 = (typeof(bits.u9))u8;
222 
223 
224 	/* expect+2: no-op cast from 'float' to 'float' [Q6] */
225 	/* expect+1: redundant cast from 'float' to 'float' before assignment [Q7] */
226 	f32 = (f32_t)f32;
227 	f32 = (f32_t)f64;
228 	f32 = (f64_t)f32;
229 	/* expect+1: no-op cast from 'double' to 'double' [Q6] */
230 	f32 = (f64_t)f64;
231 	/* expect+1: no-op cast from 'float' to 'float' [Q6] */
232 	f64 = (f32_t)f32;
233 	f64 = (f32_t)f64;
234 	/* expect+1: redundant cast from 'float' to 'double' before assignment [Q7] */
235 	f64 = (f64_t)f32;
236 	/* expect+2: no-op cast from 'double' to 'double' [Q6] */
237 	/* expect+1: redundant cast from 'double' to 'double' before assignment [Q7] */
238 	f64 = (f64_t)f64;
239 
240 
241 	/* expect+2: no-op cast from 'float _Complex' to 'float _Complex' [Q6] */
242 	/* expect+1: redundant cast from 'float _Complex' to 'float _Complex' before assignment [Q7] */
243 	c32 = (c32_t)c32;
244 	c32 = (c32_t)c64;
245 	c32 = (c64_t)c32;
246 	/* expect+1: no-op cast from 'double _Complex' to 'double _Complex' [Q6] */
247 	c32 = (c64_t)c64;
248 	/* expect+1: no-op cast from 'float _Complex' to 'float _Complex' [Q6] */
249 	c64 = (c32_t)c32;
250 	c64 = (c32_t)c64;
251 	/* expect+1: redundant cast from 'float _Complex' to 'double _Complex' before assignment [Q7] */
252 	c64 = (c64_t)c32;
253 	/* expect+2: no-op cast from 'double _Complex' to 'double _Complex' [Q6] */
254 	/* expect+1: redundant cast from 'double _Complex' to 'double _Complex' before assignment [Q7] */
255 	c64 = (c64_t)c64;
256 
257 
258 	/* Mixing real and complex floating point types. */
259 	/* expect+1: no-op cast from 'float' to 'float' [Q6] */
260 	c32 = (f32_t)f32;
261 	c32 = (c32_t)f32;
262 	/* expect+1: no-op cast from 'float' to 'float' [Q6] */
263 	c64 = (f32_t)f32;
264 	c64 = (f64_t)f32;
265 	c64 = (c32_t)f32;
266 	c64 = (c64_t)f32;
267 
268 
269 	/*
270 	 * Converting a void pointer type to an object pointer type requires
271 	 * an explicit cast in C++, as it is a narrowing conversion. In C,
272 	 * that conversion is done implicitly.
273 	 */
274 
275 	/* expect+1: redundant cast from 'pointer to void' to 'pointer to char' before assignment [Q7] */
276 	str = (char *)allocate();
277 	/* expect+1: redundant cast from 'pointer to void' to 'pointer to const char' before assignment [Q7] */
278 	cstr = (const char *)allocate();
279 	cstr = (char *)allocate();
280 
281 	/* expect+2: no-op cast from 'pointer to char' to 'pointer to char' [Q6] */
282 	/* expect+1: redundant cast from 'pointer to char' to 'pointer to char' before assignment [Q7] */
283 	str = (str_t)str;
284 	str = (str_t)cstr;
285 	/* expect+1: warning: operator '=' discards 'const' from 'pointer to const char' [128] */
286 	str = (cstr_t)str;
287 	/* expect+2: no-op cast from 'pointer to const char' to 'pointer to const char' [Q6] */
288 	/* expect+1: warning: operator '=' discards 'const' from 'pointer to const char' [128] */
289 	str = (cstr_t)cstr;
290 	/* expect+1: no-op cast from 'pointer to char' to 'pointer to char' [Q6] */
291 	cstr = (str_t)str;
292 	cstr = (str_t)cstr;
293 	cstr = (cstr_t)str;
294 	/* expect+2: no-op cast from 'pointer to const char' to 'pointer to const char' [Q6] */
295 	/* expect+1: redundant cast from 'pointer to const char' to 'pointer to const char' before assignment [Q7] */
296 	cstr = (cstr_t)cstr;
297 
298 	/* expect+2: no-op cast from 'pointer to char' to 'pointer to char' [Q6] */
299 	/* expect+1: redundant cast from 'pointer to char' to 'pointer to char' before assignment [Q7] */
300 	str = (str_t)str;
301 	str = (str_t)vstr;
302 	/* expect+1: warning: operator '=' discards 'volatile' from 'pointer to volatile char' [128] */
303 	str = (vstr_t)str;
304 	/* expect+2: no-op cast from 'pointer to volatile char' to 'pointer to volatile char' [Q6] */
305 	/* expect+1: warning: operator '=' discards 'volatile' from 'pointer to volatile char' [128] */
306 	str = (vstr_t)vstr;
307 	/* expect+1: no-op cast from 'pointer to char' to 'pointer to char' [Q6] */
308 	vstr = (str_t)str;
309 	vstr = (str_t)vstr;
310 	vstr = (vstr_t)str;
311 	/* expect+2: no-op cast from 'pointer to volatile char' to 'pointer to volatile char' [Q6] */
312 	/* expect+1: redundant cast from 'pointer to volatile char' to 'pointer to volatile char' before assignment [Q7] */
313 	vstr = (vstr_t)vstr;
314 
315 	/* expect+1: warning: operator '=' discards 'const volatile' from 'pointer to const volatile char' [128] */
316 	str = cvstr;
317 	/* expect+1: warning: operator '=' discards 'volatile' from 'pointer to const volatile char' [128] */
318 	cstr = cvstr;
319 	/* expect+1: warning: operator '=' discards 'const' from 'pointer to const volatile char' [128] */
320 	vstr = cvstr;
321 }
322 
323 /*
324  * Octal numbers were common in the 1970s, especially on 36-bit machines.
325  * 50 years later, they are still used in numeric file permissions.
326  */
327 void
328 Q8(void)
329 {
330 
331 	u16 = 0;
332 	u16 = 000000;
333 	/* expect+1: octal number '0644' [Q8] */
334 	u16 = 0644;
335 	/* expect+1: octal number '0000644' [Q8] */
336 	u16 = 0000644;
337 }
338 
339 int
340 Q9(int x)
341 {
342 	switch (x) {
343 	case 0:
344 		return 0;
345 	case 1:
346 		/* expect+1: parenthesized return value [Q9] */
347 		return (0);
348 	case 2:
349 		return +(0);
350 	case 3:
351 		return -(13);
352 	case 4:
353 		/* expect+2: comma operator with types 'int' and 'int' [Q12] */
354 		/* expect+1: parenthesized return value [Q9] */
355 		return (0), (1);
356 	case 5:
357 		/* expect+2: comma operator with types 'int' and 'int' [Q12] */
358 		/* expect+1: parenthesized return value [Q9] */
359 		return (0, 1);
360 	case 6:
361 		/* expect+1: comma operator with types 'int' and 'int' [Q12] */
362 		return 0, 1;
363 	case 7:
364 		/* expect+1: implicit conversion from floating point 'double' to integer 'int' [Q1] */
365 		return 0.0;
366 	case 8:
367 		/* expect+2: parenthesized return value [Q9] */
368 		/* expect+1: implicit conversion from floating point 'double' to integer 'int' [Q1] */
369 		return (0.0);
370 	case 9:
371 		return
372 # 373 "queries.c" 3 4
373 		((void *)0)
374 # 375 "queries.c"
375 		/* expect+1: warning: illegal combination of integer 'int' and pointer 'pointer to void' [183] */
376 		;
377 	case 10:
378 		/* expect+1: warning: illegal combination of integer 'int' and pointer 'pointer to void' [183] */
379 		return (void *)(0);
380 	default:
381 		return 0;
382 	}
383 }
384 
385 void
386 Q10(void)
387 {
388 	int a, b, c;
389 
390 	/* expect+2: chained assignment with '=' and '=' [Q10] */
391 	/* expect+1: chained assignment with '=' and '=' [Q10] */
392 	a = b = c = 0;
393 
394 	/* expect+2: chained assignment with '*=' and '-=' [Q10] */
395 	/* expect+1: chained assignment with '+=' and '*=' [Q10] */
396 	a += b *= c -= 0;
397 }
398 
399 void
400 Q11(void)
401 {
402 	/* expect+1: static variable 'static_var_no_init' in function [Q11] */
403 	static int static_var_no_init;
404 	/* expect+1: static variable 'static_var_init' in function [Q11] */
405 	static int static_var_init = 1;
406 
407 	static_var_no_init++;
408 	static_var_init++;
409 }
410 
411 void
412 Q12(void)
413 {
414 	/* expect+1: comma operator with types 'void' and '_Bool' [Q12] */
415 	if (Q11(), cond)
416 		return;
417 
418 	/* expect+5: implicit conversion changes sign from 'unsigned char' to 'int' [Q3] */
419 	/* expect+4: implicit conversion changes sign from 'int' to 'unsigned short' [Q3] */
420 	/* expect+3: implicit conversion changes sign from 'unsigned short' to 'int' [Q3] */
421 	/* expect+2: implicit conversion changes sign from 'int' to 'unsigned int' [Q3] */
422 	/* expect+1: comma operator with types 'unsigned short' and 'unsigned int' [Q12] */
423 	u16 += u8, u32 += u16;
424 }
425 
426 /* expect+1: redundant 'extern' in function declaration of 'extern_Q13' [Q13] */
427 extern void extern_Q13(void);
428 void extern_Q13(void);
429 /* expect+1: redundant 'extern' in function declaration of 'extern_Q13' [Q13] */
430 extern void extern_Q13(void), *extern_ptr;
431 
432 int
433 Q14(signed char sc, unsigned char uc, int wc)
434 {
435 	// Plain 'char' is platform-dependent, see queries-{schar,uchar}.c.
436 
437 	if (sc == 'c' || sc == L'w' || sc == 92 || sc == 0)
438 		return 2;
439 	/* expect+4: implicit conversion changes sign from 'unsigned char' to 'int' [Q3] */
440 	/* expect+3: implicit conversion changes sign from 'unsigned char' to 'int' [Q3] */
441 	/* expect+2: implicit conversion changes sign from 'unsigned char' to 'int' [Q3] */
442 	/* expect+1: implicit conversion changes sign from 'unsigned char' to 'int' [Q3] */
443 	if (uc == 'c' || uc == L'w' || uc == 92 || uc == 0)
444 		return 3;
445 	if (wc == 'c' || wc == L'w' || wc == 92 || wc == 0)
446 		return 4;
447 	return 5;
448 }
449 
450 void *
451 Q15(void)
452 {
453 	/* expect+1: implicit conversion from integer 0 to pointer 'pointer to void' [Q15] */
454 	void *ptr_from_int = 0;
455 	/* expect+1: implicit conversion from integer 0 to pointer 'pointer to void' [Q15] */
456 	void *ptr_from_uint = 0U;
457 	/* expect+1: implicit conversion from integer 0 to pointer 'pointer to void' [Q15] */
458 	void *ptr_from_long = 0L;
459 
460 	ptr_from_int = &ptr_from_int;
461 	ptr_from_uint = &ptr_from_uint;
462 	ptr_from_long = &ptr_from_long;
463 
464 	void_ptr = (void *)0;
465 	const_void_ptr = (const void *)0;
466 
467 	/* expect+1: implicit conversion from integer 0 to pointer 'pointer to void' [Q15] */
468 	return 0;
469 }
470 
471 /*
472  * Even though C99 6.2.2p4 allows a 'static' declaration followed by a
473  * non-'static' declaration, it may look confusing.
474  */
475 static void Q16(void);
476 /* expect+3: 'Q16' was declared 'static', now non-'static' [Q16] */
477 /* expect+2: warning: static function 'Q16' unused [236] */
478 void
479 Q16(void)
480 {
481 }
482 
483 /* expect+1: invisible character U+0009 in character constant [Q17] */
484 char Q17_char[] = { ' ', '\0', '	' };
485 /* expect+1: invisible character U+0009 in string literal [Q17] */
486 char Q17_char_string[] = " \0	";
487 /* expect+1: invisible character U+0009 in character constant [Q17] */
488 int Q17_wide[] = { L' ', L'\0', L'	' };
489 /* expect+1: invisible character U+0009 in string literal [Q17] */
490 int Q17_wide_string[] = L" \0	";
491 
492 /* For Q18, see queries_schar.c and queries_uchar.c. */
493 
494 void
495 convert_from_integer_to_floating(void)
496 {
497 	/* expect+1: implicit conversion from integer 'unsigned int' to floating point 'float' [Q19] */
498 	f32 = 0xffff0000;
499 	/* expect+1: implicit conversion from integer 'unsigned int' to floating point 'float' [Q19] */
500 	f32 = 0xffffffff;
501 	/* expect+1: implicit conversion from integer 'int' to floating point 'float' [Q19] */
502 	f32 = s32;
503 	/* expect+1: implicit conversion from integer 'unsigned int' to floating point 'float' [Q19] */
504 	f32 = u32;
505 	/* expect+1: implicit conversion from integer 'int' to floating point 'double' [Q19] */
506 	f64 = s32;
507 	/* expect+1: implicit conversion from integer 'unsigned int' to floating point 'double' [Q19] */
508 	f64 = u32;
509 	/* expect+1: implicit conversion from integer 'long long' to floating point 'double' [Q19] */
510 	f64 = s64;
511 	/* expect+1: implicit conversion from integer 'unsigned long long' to floating point 'double' [Q19] */
512 	f64 = u64;
513 
514 	f32 = 0.0F;
515 	f32 = 0.0;
516 	f64 = 0.0;
517 
518 	f64 = (double)0;
519 	f64 = (double)u32;
520 }
521 
522 // C allows implicit narrowing conversions from a void pointer to an arbitrary
523 // object pointer. C++ doesn't allow this conversion since it is narrowing.
524 void
525 Q20_void_pointer_conversion(void)
526 {
527 	/* expect+1: warning: operator '=' discards 'const' from 'pointer to const void' [128] */
528 	void_ptr = const_void_ptr;
529 	const_void_ptr = void_ptr;
530 	/* expect+1: implicit narrowing conversion from void pointer to 'pointer to int' [Q20] */
531 	int_ptr = void_ptr;
532 	/* expect+1: redundant cast from 'pointer to void' to 'pointer to int' before assignment [Q7] */
533 	int_ptr = (int *)void_ptr;
534 	/* expect+1: implicit narrowing conversion from void pointer to 'pointer to char' [Q20] */
535 	char_ptr = void_ptr;
536 	void_ptr = char_ptr;
537 	/* expect+1: implicit narrowing conversion from void pointer to 'pointer to int' [Q20] */
538 	int_ptr = void_ptr;
539 	/* expect+1: warning: illegal combination of 'pointer to int' and 'pointer to char', op '=' [124] */
540 	int_ptr = char_ptr;
541 	/* expect+1: warning: illegal combination of 'pointer to char' and 'pointer to int', op '=' [124] */
542 	char_ptr = int_ptr;
543 
544 	int_ptr = (void *)0;
545 }
546