expr_sizeof.c revision 1.19 1 1.19 rillig /* $NetBSD: expr_sizeof.c,v 1.19 2025/04/12 15:49:49 rillig Exp $ */
2 1.1 rillig # 3 "expr_sizeof.c"
3 1.1 rillig
4 1.1 rillig /*
5 1.1 rillig * C99 6.5.3.4 "The sizeof operator"
6 1.1 rillig * C11 6.5.3.4 "The sizeof operator"
7 1.1 rillig */
8 1.1 rillig
9 1.5 rillig /* lint1-extra-flags: -X 351 */
10 1.5 rillig
11 1.1 rillig /*
12 1.1 rillig * A sizeof expression can either take a type name or an expression.
13 1.1 rillig */
14 1.11 rillig
15 1.1 rillig void sink(unsigned long);
16 1.1 rillig
17 1.1 rillig struct {
18 1.1 rillig int member;
19 1.1 rillig } s, *ps;
20 1.1 rillig
21 1.1 rillig /*
22 1.1 rillig * In a sizeof expression taking a type name, the type name must be enclosed
23 1.1 rillig * in parentheses.
24 1.1 rillig */
25 1.1 rillig /* expect+1: error: negative array dimension (-4) [20] */
26 1.1 rillig typedef int sizeof_int[-(int)sizeof(int)];
27 1.1 rillig
28 1.1 rillig /*
29 1.1 rillig * In a sizeof expression taking an expression, the expression may or may not
30 1.1 rillig * be enclosed in parentheses, like any other expression.
31 1.1 rillig */
32 1.1 rillig /* expect+1: error: negative array dimension (-4) [20] */
33 1.1 rillig typedef int sizeof_paren_zero[-(int)sizeof(0)];
34 1.1 rillig /* expect+1: error: negative array dimension (-4) [20] */
35 1.1 rillig typedef int sizeof_zero[-(int)sizeof 0];
36 1.1 rillig
37 1.1 rillig /*
38 1.1 rillig * Even though 's' is not a constant expression, 'sizeof s' is.
39 1.1 rillig */
40 1.1 rillig /* expect+1: error: negative array dimension (-4) [20] */
41 1.1 rillig typedef int sizeof_global_var[-(int)sizeof s];
42 1.1 rillig /* expect+1: error: negative array dimension (-4) [20] */
43 1.1 rillig typedef int sizeof_paren_global_var[-(int)sizeof(s)];
44 1.1 rillig
45 1.1 rillig /*
46 1.1 rillig * Even though 'sizeof(s)' may look like a function call expression, the
47 1.1 rillig * parentheses around 's' are ordinary parentheses and do not influence the
48 1.2 rillig * precedence.
49 1.2 rillig *
50 1.2 rillig * Therefore, the '.' following the '(s)' takes precedence over the 'sizeof'.
51 1.2 rillig * Same for the '->' following the '(ps)'. Same for the '[0]' following the
52 1.2 rillig * '(arr)'.
53 1.1 rillig */
54 1.1 rillig /* expect+1: error: negative array dimension (-4) [20] */
55 1.1 rillig typedef int sizeof_paren_global_struct_member[-(int)sizeof(s).member];
56 1.1 rillig /* expect+1: error: negative array dimension (-4) [20] */
57 1.1 rillig typedef int sizeof_paren_global_ptr_struct_member[-(int)sizeof(ps)->member];
58 1.2 rillig int arr[] = { 1, 2, 3 };
59 1.2 rillig /* expect+1: error: negative array dimension (-3) [20] */
60 1.2 rillig typedef int arr_count[-(int)sizeof(arr) / (int)sizeof(arr)[0]];
61 1.2 rillig
62 1.2 rillig /* FIXME: 'n' is actually used, for the variable length array. */
63 1.13 rillig /* expect+2: warning: parameter 'n' unused in function 'variable_length_array' [231] */
64 1.2 rillig void
65 1.2 rillig variable_length_array(int n)
66 1.2 rillig {
67 1.2 rillig int local_arr[n + 5];
68 1.3 rillig
69 1.3 rillig /*
70 1.3 rillig * Since the array length is not constant, it cannot be used in a
71 1.4 rillig * typedef. Code like this is already rejected by the compiler. For
72 1.3 rillig * simplicity, lint assumes that the array has length 1.
73 1.3 rillig */
74 1.2 rillig /* expect+1: error: negative array dimension (-4) [20] */
75 1.2 rillig typedef int sizeof_local_arr[-(int)sizeof(local_arr)];
76 1.2 rillig }
77 1.6 rillig
78 1.7 rillig void
79 1.7 rillig bit_fields(void)
80 1.7 rillig {
81 1.7 rillig struct {
82 1.7 rillig _Bool flag0:1;
83 1.7 rillig _Bool flag1:1;
84 1.7 rillig _Bool flag2:1;
85 1.7 rillig } flags;
86 1.7 rillig /* expect+1: error: negative array dimension (-1) [20] */
87 1.7 rillig typedef int sizeof_flags[-(int)sizeof(flags)];
88 1.7 rillig
89 1.7 rillig struct {
90 1.7 rillig struct {
91 1.7 rillig _Bool flag0:1;
92 1.7 rillig _Bool flag1:1;
93 1.7 rillig _Bool flag2:1;
94 1.7 rillig };
95 1.7 rillig } anonymous_flags;
96 1.10 rillig /* expect+1: error: negative array dimension (-1) [20] */
97 1.7 rillig typedef int sizeof_anonymous_flags[-(int)sizeof(anonymous_flags)];
98 1.7 rillig
99 1.7 rillig struct {
100 1.7 rillig unsigned int bits0:16;
101 1.7 rillig unsigned int bits1:16;
102 1.7 rillig } same_storage_unit;
103 1.7 rillig /* expect+1: error: negative array dimension (-4) [20] */
104 1.7 rillig typedef int sizeof_same_storage_unit[-(int)sizeof(same_storage_unit)];
105 1.7 rillig
106 1.7 rillig // Detect whether a bit-field can span multiple storage units.
107 1.7 rillig // If so, the size is 12, if not, the size is 16.
108 1.7 rillig struct {
109 1.7 rillig unsigned int bits0:24;
110 1.7 rillig unsigned int bits1:24;
111 1.7 rillig unsigned int bits2:24;
112 1.7 rillig unsigned int bits3:24;
113 1.7 rillig } cross_storage_unit;
114 1.7 rillig /* expect+1: error: negative array dimension (-16) [20] */
115 1.7 rillig typedef int sizeof_cross_storage_unit[-(int)sizeof(cross_storage_unit)];
116 1.8 rillig
117 1.8 rillig /*
118 1.8 rillig * The bit-fields in a struct may be merged into the same storage
119 1.8 rillig * units, even if their types differ. GCC 10, Clang 15 and lint all
120 1.9 rillig * agree in packing the first group of bit-fields and the char into
121 1.9 rillig * 4 bytes, even though their underlying types differ. The second
122 1.9 rillig * group of bit-fields gets its own storage unit.
123 1.8 rillig */
124 1.8 rillig struct mixed {
125 1.8 rillig _Bool flag0:1;
126 1.8 rillig signed int signed0:1;
127 1.8 rillig unsigned int unsigned0:1;
128 1.9 rillig char ch[3];
129 1.8 rillig _Bool flag1:1;
130 1.8 rillig signed int signed1:1;
131 1.8 rillig unsigned int unsigned1:1;
132 1.8 rillig } mixed;
133 1.9 rillig /* expect+1: error: negative array dimension (-8) [20] */
134 1.8 rillig typedef int sizeof_mixed[-(int)sizeof(mixed)];
135 1.14 rillig /* expect+3: error: negative array dimension (-1) [20] */
136 1.8 rillig typedef int offsetof_mixed_ch[
137 1.8 rillig -(int)__builtin_offsetof(struct mixed, ch)
138 1.8 rillig ];
139 1.7 rillig }
140 1.7 rillig
141 1.6 rillig /*
142 1.6 rillig * Ensure that anonymous structs and unions are handled correctly. They were
143 1.6 rillig * added in C11, and lint did not properly support them until 2023.
144 1.6 rillig */
145 1.6 rillig void
146 1.6 rillig anonymous_struct_and_union(void)
147 1.6 rillig {
148 1.6 rillig struct {
149 1.6 rillig union {
150 1.6 rillig unsigned char uc16[16];
151 1.6 rillig unsigned char uc32[32];
152 1.6 rillig };
153 1.6 rillig } su_16_32;
154 1.12 rillig /* expect+1: error: negative array dimension (-32) [20] */
155 1.6 rillig typedef int sizeof_su_16_32[-(int)sizeof(su_16_32)];
156 1.6 rillig
157 1.6 rillig union {
158 1.6 rillig struct {
159 1.6 rillig unsigned char uc16[16];
160 1.6 rillig unsigned char uc32[32];
161 1.6 rillig };
162 1.6 rillig } us_16_32;
163 1.6 rillig /* expect+1: error: negative array dimension (-48) [20] */
164 1.6 rillig typedef int sizeof_us_16_32[-(int)sizeof(us_16_32)];
165 1.6 rillig }
166 1.11 rillig
167 1.11 rillig
168 1.11 rillig void
169 1.11 rillig sizeof_errors(void)
170 1.11 rillig {
171 1.11 rillig /* expect+1: error: cannot take size/alignment of void [146] */
172 1.11 rillig typedef int sizeof_void[-(int)sizeof(void)];
173 1.11 rillig
174 1.11 rillig /*
175 1.11 rillig * A 'void array' gets replaced with an 'int array' before
176 1.11 rillig * type_size_in_bits gets to see it, thus the 256 * 4 = 1024.
177 1.11 rillig */
178 1.19 rillig /* expect+2: error: invalid use of 'void' [18] */
179 1.11 rillig /* expect+1: error: negative array dimension (-1024) [20] */
180 1.11 rillig typedef int sizeof_void_array[-(int)sizeof(void[256])];
181 1.11 rillig
182 1.11 rillig /* expect+1: warning: enum 'incomplete_enum' never defined [235] */
183 1.11 rillig enum incomplete_enum;
184 1.11 rillig /* expect+2: warning: cannot take size/alignment of incomplete type [143] */
185 1.11 rillig /* expect+1: error: negative array dimension (-4) [20] */
186 1.11 rillig typedef int sizeof_incomplete_enum[-(int)sizeof(enum incomplete_enum)];
187 1.11 rillig }
188 1.11 rillig
189 1.11 rillig
190 1.11 rillig /*
191 1.11 rillig * Due to the 'double' member, the alignment of this struct is 8, so the size
192 1.11 rillig * has to be 24 (or at least divisible by 8), otherwise the 'double' member
193 1.11 rillig * would not get the correct alignment in an array of this struct.
194 1.11 rillig */
195 1.11 rillig struct s24 {
196 1.11 rillig char c0;
197 1.11 rillig double d8;
198 1.11 rillig char c16;
199 1.11 rillig };
200 1.11 rillig /* expect+1: error: negative array dimension (-24) [20] */
201 1.11 rillig typedef int sizeof_s24[-(int)sizeof(struct s24)];
202 1.15 rillig
203 1.15 rillig void
204 1.15 rillig sizeof_array_parameter(short arr[12345])
205 1.15 rillig {
206 1.15 rillig // The size of an array parameter is the size of the decayed pointer.
207 1.15 rillig // Subtracting 'sizeof(void *)' makes the test platform-independent.
208 1.15 rillig typedef int sizeof_arr[-(int)(sizeof arr - sizeof(void *))];
209 1.15 rillig
210 1.15 rillig // The 2 comes from 'sizeof(short)', as the type 'array[size] of elem'
211 1.15 rillig // decays into the type 'pointer to elem', not 'pointer to array[size]
212 1.15 rillig // of elem'.
213 1.15 rillig /* expect+1: error: negative array dimension (-2) [20] */
214 1.15 rillig typedef int sizeof_arr_elem[-(int)(sizeof *arr)];
215 1.15 rillig }
216 1.16 rillig
217 1.16 rillig
218 1.16 rillig void
219 1.16 rillig sequence_of_structs(void)
220 1.16 rillig {
221 1.16 rillig typedef unsigned char uint8_t;
222 1.18 rillig typedef unsigned short uint16_t;
223 1.16 rillig typedef unsigned int uint32_t;
224 1.18 rillig typedef unsigned long long uint64_t;
225 1.16 rillig
226 1.16 rillig union fp_addr {
227 1.16 rillig uint64_t fa_64;
228 1.16 rillig struct {
229 1.16 rillig uint32_t fa_off;
230 1.16 rillig uint16_t fa_seg;
231 1.16 rillig uint16_t fa_opcode;
232 1.16 rillig } fa_32;
233 1.16 rillig } __packed _Alignas(4);
234 1.16 rillig
235 1.16 rillig struct fpacc87 {
236 1.16 rillig uint64_t f87_mantissa;
237 1.16 rillig uint16_t f87_exp_sign;
238 1.16 rillig } __packed _Alignas(2);
239 1.16 rillig
240 1.16 rillig // FIXME: This otherwise unused struct declaration influences the
241 1.16 rillig // offsets checked below. Without this struct, sizeof(struct save87)
242 1.16 rillig // is calculated correctly as 108 below.
243 1.16 rillig struct fpaccfx {
244 1.16 rillig struct fpacc87 r _Alignas(16);
245 1.16 rillig };
246 1.16 rillig
247 1.16 rillig struct save87 {
248 1.16 rillig uint16_t s87_cw _Alignas(4);
249 1.16 rillig uint16_t s87_sw _Alignas(4);
250 1.16 rillig uint16_t s87_tw _Alignas(4);
251 1.16 rillig union fp_addr s87_ip;
252 1.16 rillig union fp_addr s87_dp;
253 1.16 rillig struct fpacc87 s87_ac[8];
254 1.16 rillig };
255 1.16 rillig
256 1.16 rillig /* expect+1: error: negative array dimension (-20) [20] */
257 1.17 rillig typedef int o1[-(int)((unsigned long)(&(((struct save87 *)0)->s87_dp)))];
258 1.16 rillig // FIXME: must be 28.
259 1.16 rillig /* expect+1: error: negative array dimension (-32) [20] */
260 1.17 rillig typedef int o2[-(int)((unsigned long)(&(((struct save87 *)0)->s87_ac)))];
261 1.16 rillig // FIXME: must be 108.
262 1.16 rillig /* expect+1: error: negative array dimension (-112) [20] */
263 1.16 rillig typedef int reveal[-(int)sizeof(struct save87)];
264 1.16 rillig }
265