summaryrefslogtreecommitdiff
path: root/tests/usr.bin/xlint/lint1/expr_fold.c
blob: 21ccc2b859defb4e47baf81307feb3c660404de5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
/*	$NetBSD: expr_fold.c,v 1.9 2023/07/02 18:14:44 rillig Exp $	*/
# 3 "expr_fold.c"

/*
 * Test folding of constant expressions.
 */

/* lint1-extra-flags: -h -X 351 */

/*
 * On ILP32 platforms, the integer constant 2147483648 cannot be represented
 * as 'int' or 'long', therefore it becomes 'long long'.  This would
 * influence the type names in the diagnostics.
 */
/* lint1-only-if: lp64 */

void take_bool(_Bool);
void take_int(int);
void take_uint(unsigned int);

/*
 * C99 6.4.4.1p5 defines that decimal integer constants without suffix get
 * one of the signed integer types. On the other hand, octal and hexadecimal
 * constants get either a signed or unsigned type, whichever fits first.
 */

void
fold_uplus(void)
{
	take_int(+(0));
	take_int(+(2147483647));
	/* expect+1: warning: conversion of 'long' to 'int' is out of range, arg #1 [295] */
	take_int(+(2147483648));
	/* expect+1: warning: conversion of 'long' to 'int' is out of range, arg #1 [295] */
	take_int(+(4294967295));

	take_uint(+(0));
	take_uint(+(2147483647));
	take_uint(+(2147483648));
	take_uint(+(4294967295));

	/*
	 * Hexadecimal constants and constants with the suffix 'U' get either
	 * a signed or an unsigned integer type, so no warning here.
	 */
	take_uint(+(2147483648U));
	take_uint(+(0x80000000));
	take_uint(+(0x80000000U));
}

void
fold_uminus(void)
{
	take_int(-(0));
	take_int(-(2147483647));

	take_int(-(2147483648));

	/* The '-' is an operator, it is not part of the integer constant. */
	take_int(-2147483648);

	/* expect+2: warning: integer overflow detected, op '+' [141] */
	/* expect+1: warning: integer overflow detected, op '-' [141] */
	take_int(-(2147483647 + 1));
	/* expect+1: warning: integer overflow detected, op '-' [141] */
	take_int(-(-2147483647 - 1));
	/* expect+1: warning: conversion of 'long' to 'int' is out of range, arg #1 [295] */
	take_int(-(4294967295));

	take_uint(-(0));
	/* expect+1: warning: conversion of negative constant to unsigned type, arg #1 [296] */
	take_uint(-(2147483647));
	/* expect+1: warning: conversion of negative constant to unsigned type, arg #1 [296] */
	take_uint(-(2147483648));
	/* expect+1: warning: conversion of negative constant to unsigned type, arg #1 [296] */
	take_uint(-(4294967295));
}

void
fold_compl(void)
{
	take_int(~(0));
	take_int(~(2147483647));
	/* expect+1: warning: conversion of 'long' to 'int' is out of range, arg #1 [295] */
	take_int(~(2147483648));
	/* expect+1: warning: conversion of 'long' to 'int' is out of range, arg #1 [295] */
	take_int(~(4294967295));

	/* expect+1: warning: conversion of negative constant to unsigned type, arg #1 [296] */
	take_uint(~(0));
	/* expect+1: warning: conversion of negative constant to unsigned type, arg #1 [296] */
	take_uint(~(2147483647));
	/* expect+1: warning: conversion of negative constant to unsigned type, arg #1 [296] */
	take_uint(~(2147483648));
	/* expect+1: warning: conversion of negative constant to unsigned type, arg #1 [296] */
	take_uint(~(4294967295));
}

void
fold_mult(void)
{
	take_int(32767 * 65536);
	/* expect+1: warning: integer overflow detected, op '*' [141] */
	take_int(32768 * 65536);
	/* expect+1: warning: integer overflow detected, op '*' [141] */
	take_int(65536 * 65536);

	take_uint(32767 * 65536U);
	take_uint(32768 * 65536U);
	/* expect+1: warning: integer overflow detected, op '*' [141] */
	take_uint(65536 * 65536U);
}

void
fold_div(void)
{
	/* expect+3: error: division by 0 [139] */
	/* XXX: The following message is redundant. */
	/* expect+1: warning: integer overflow detected, op '/' [141] */
	take_int(0 / 0);

	/* expect+1: warning: conversion of 'long' to 'int' is out of range, arg #1 [295] */
	take_int(-2147483648 / -1);
}

void
fold_mod(void)
{
	/* expect+1: error: modulus by 0 [140] */
	take_int(0 % 0);
	/* expect+1: error: modulus by 0 [140] */
	take_int(0 % 0U);
	/* expect+1: error: modulus by 0 [140] */
	take_int(0U % 0);
	/* expect+1: error: modulus by 0 [140] */
	take_int(0U % 0U);

	take_int(-2147483648 % -1);
}

void
fold_plus(void)
{
	/* expect+1: warning: integer overflow detected, op '+' [141] */
	take_int(2147483647 + 1);

	/* Assume two's complement, so no overflow. */
	take_int(-2147483647 + -1);

	/* expect+1: warning: integer overflow detected, op '+' [141] */
	take_int(-2147483647 + -2);

	/*
	 * No overflow since one of the operands is unsigned, therefore the
	 * other operand is converted to unsigned as well.
	 * See C99 6.3.1.8p1, paragraph 8 of 10.
	 */
	/* wrong integer overflow warning before tree.c 1.338 from 2021-08-19 */
	take_uint(2147483647 + 1U);
	/* wrong integer overflow warning before tree.c 1.338 from 2021-08-19 */
	take_uint(2147483647U + 1);
}

void
fold_minus(void)
{
	/* expect+1: warning: integer overflow detected, op '-' [141] */
	take_int(2147483647 - -1);
	/* Assume two's complement. */
	take_int(-2147483647 - 1);
	/* expect+1: warning: integer overflow detected, op '-' [141] */
	take_int(-2147483647 - 2);

	take_int(0 - 2147483648);
	/* expect+1: warning: integer overflow detected, op '-' [141] */
	take_uint(0 - 2147483648U);
}

void
fold_shl(void)
{
	/* expect+1: warning: integer overflow detected, op '<<' [141] */
	take_int(1 << 24 << 24);

	/* expect+1: warning: integer overflow detected, op '<<' [141] */
	take_uint(1U << 24 << 24);

	/* FIXME: undefined behavior in 'fold' at 'uint64_t << 104'. */
	/* expect+1: warning: shift amount 104 is greater than bit-size 32 of 'unsigned int' [122] */
	take_uint(1U << 24 << 104);
}

void
fold_shr(void)
{
	take_int(16777216 >> 24);

	take_int(16777216 >> 25);

	/* FIXME: undefined behavior in 'fold' at 'uint64_t >> 104'. */
	/* expect+1: warning: shift amount 104 is greater than bit-size 32 of 'int' [122] */
	take_int(16777216 >> 104);
}

void
fold_lt(void)
{
	take_bool(1 < 3);
	take_bool(3 < 1);
}

void
fold_le(void)
{
	take_bool(1 <= 3);
	take_bool(3 <= 1);
}

void
fold_ge(void)
{
	take_bool(1 >= 3);
	take_bool(3 >= 1);
}

void
fold_gt(void)
{
	take_bool(1 > 3);
	take_bool(3 > 1);
}

void
fold_eq(void)
{
	take_bool(1 == 3);
	take_bool(3 == 1);
}

void
fold_ne(void)
{
	take_bool(1 != 3);
	take_bool(3 != 1);
}

void
fold_bitand(void)
{
	take_bool(1 & 3);
	take_bool(3 & 1);
}

void
fold_bitxor(void)
{
	take_bool(1 ^ 3);
	take_bool(3 ^ 1);
}

void
fold_bitor(void)
{
	take_bool(1 | 3);
	take_bool(3 | 1);
}

/*
 * The following expression originated in vndcompress.c 1.29 from 2017-07-29,
 * where line 310 contained a seemingly harmless compile-time assertion that
 * expanded to a real monster expression.
 *
 * __CTASSERT(MUL_OK(uint64_t, MAX_N_BLOCKS, MAX_BLOCKSIZE));
 *
 * Before tree.c 1.345 from 2021-08-22, lint wrongly assumed that the result
 * of all binary operators were the common arithmetic type, but that was
 * wrong for the comparison operators.  The expression '1ULL < 2ULL' does not
 * have type 'unsigned long long' but 'int' in default mode, or '_Bool' in
 * strict bool mode.
 */
struct ctassert5_struct {
	unsigned int member:
	    /*CONSTCOND*/
	    0xfffffffeU
	    <=
		((1ULL << 63) + 1 < 1 ? ~(1ULL << 63) : ~0ULL) / 0xfffffe00U
		? 1
		: -1;
};

/*
 * Since Makefile.inc 1.21 from 2022-04-08 (which added -ftrapv) and before
 * tree.c 1.436 from 2022-04-20, lint crashed with an integer overflow when
 * calculating '-(uint64_t)INT64_MIN' in val_t.u.integer.
 */
void
unary_minus_overflow(unsigned long long val)
{
	/* expect+1: warning: integer overflow detected, op '-' [141] */
	if (val > -(unsigned long long)(-0x7fffffffffffffffL - 1))
		return;
}