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