expr_sizeof.c revision 1.11 1 /* $NetBSD: expr_sizeof.c,v 1.11 2023/06/30 16:39:17 rillig Exp $ */
2 # 3 "expr_sizeof.c"
3
4 /*
5 * C99 6.5.3.4 "The sizeof operator"
6 * C11 6.5.3.4 "The sizeof operator"
7 */
8
9 /* lint1-extra-flags: -X 351 */
10
11 /*
12 * A sizeof expression can either take a type name or an expression.
13 */
14
15 void sink(unsigned long);
16
17 struct {
18 int member;
19 } s, *ps;
20
21 /*
22 * In a sizeof expression taking a type name, the type name must be enclosed
23 * in parentheses.
24 */
25 /* expect+1: error: negative array dimension (-4) [20] */
26 typedef int sizeof_int[-(int)sizeof(int)];
27
28 /*
29 * In a sizeof expression taking an expression, the expression may or may not
30 * be enclosed in parentheses, like any other expression.
31 */
32 /* expect+1: error: negative array dimension (-4) [20] */
33 typedef int sizeof_paren_zero[-(int)sizeof(0)];
34 /* expect+1: error: negative array dimension (-4) [20] */
35 typedef int sizeof_zero[-(int)sizeof 0];
36
37 /*
38 * Even though 's' is not a constant expression, 'sizeof s' is.
39 */
40 /* expect+1: error: negative array dimension (-4) [20] */
41 typedef int sizeof_global_var[-(int)sizeof s];
42 /* expect+1: error: negative array dimension (-4) [20] */
43 typedef int sizeof_paren_global_var[-(int)sizeof(s)];
44
45 /*
46 * Even though 'sizeof(s)' may look like a function call expression, the
47 * parentheses around 's' are ordinary parentheses and do not influence the
48 * precedence.
49 *
50 * Therefore, the '.' following the '(s)' takes precedence over the 'sizeof'.
51 * Same for the '->' following the '(ps)'. Same for the '[0]' following the
52 * '(arr)'.
53 */
54 /* expect+1: error: negative array dimension (-4) [20] */
55 typedef int sizeof_paren_global_struct_member[-(int)sizeof(s).member];
56 /* expect+1: error: negative array dimension (-4) [20] */
57 typedef int sizeof_paren_global_ptr_struct_member[-(int)sizeof(ps)->member];
58 int arr[] = { 1, 2, 3 };
59 /* expect+1: error: negative array dimension (-3) [20] */
60 typedef int arr_count[-(int)sizeof(arr) / (int)sizeof(arr)[0]];
61
62 /* FIXME: 'n' is actually used, for the variable length array. */
63 /* expect+2: warning: argument 'n' unused in function 'variable_length_array' [231] */
64 void
65 variable_length_array(int n)
66 {
67 int local_arr[n + 5];
68
69 /*
70 * Since the array length is not constant, it cannot be used in a
71 * typedef. Code like this is already rejected by the compiler. For
72 * simplicity, lint assumes that the array has length 1.
73 */
74 /* expect+1: error: negative array dimension (-4) [20] */
75 typedef int sizeof_local_arr[-(int)sizeof(local_arr)];
76 }
77
78 void
79 bit_fields(void)
80 {
81 struct {
82 _Bool flag0:1;
83 _Bool flag1:1;
84 _Bool flag2:1;
85 } flags;
86 /* expect+1: error: negative array dimension (-1) [20] */
87 typedef int sizeof_flags[-(int)sizeof(flags)];
88
89 struct {
90 struct {
91 _Bool flag0:1;
92 _Bool flag1:1;
93 _Bool flag2:1;
94 };
95 } anonymous_flags;
96 /* expect+1: error: negative array dimension (-1) [20] */
97 typedef int sizeof_anonymous_flags[-(int)sizeof(anonymous_flags)];
98
99 struct {
100 unsigned int bits0:16;
101 unsigned int bits1:16;
102 } same_storage_unit;
103 /* expect+1: error: negative array dimension (-4) [20] */
104 typedef int sizeof_same_storage_unit[-(int)sizeof(same_storage_unit)];
105
106 // Detect whether a bit-field can span multiple storage units.
107 // If so, the size is 12, if not, the size is 16.
108 struct {
109 unsigned int bits0:24;
110 unsigned int bits1:24;
111 unsigned int bits2:24;
112 unsigned int bits3:24;
113 } cross_storage_unit;
114 /* expect+1: error: negative array dimension (-16) [20] */
115 typedef int sizeof_cross_storage_unit[-(int)sizeof(cross_storage_unit)];
116
117 /*
118 * The bit-fields in a struct may be merged into the same storage
119 * units, even if their types differ. GCC 10, Clang 15 and lint all
120 * agree in packing the first group of bit-fields and the char into
121 * 4 bytes, even though their underlying types differ. The second
122 * group of bit-fields gets its own storage unit.
123 */
124 struct mixed {
125 _Bool flag0:1;
126 signed int signed0:1;
127 unsigned int unsigned0:1;
128 char ch[3];
129 _Bool flag1:1;
130 signed int signed1:1;
131 unsigned int unsigned1:1;
132 } mixed;
133 /* expect+1: error: negative array dimension (-8) [20] */
134 typedef int sizeof_mixed[-(int)sizeof(mixed)];
135 /* FIXME: Implement build_offsetof correctly. */
136 /* expect+3: error: negative array dimension (-8) [20] */
137 typedef int offsetof_mixed_ch[
138 -(int)__builtin_offsetof(struct mixed, ch)
139 ];
140 }
141
142 /*
143 * Ensure that anonymous structs and unions are handled correctly. They were
144 * added in C11, and lint did not properly support them until 2023.
145 */
146 void
147 anonymous_struct_and_union(void)
148 {
149 struct {
150 union {
151 unsigned char uc16[16];
152 unsigned char uc32[32];
153 };
154 } su_16_32;
155 /* FIXME: Must be 32, not 48. */
156 /* expect+1: error: negative array dimension (-48) [20] */
157 typedef int sizeof_su_16_32[-(int)sizeof(su_16_32)];
158
159 union {
160 struct {
161 unsigned char uc16[16];
162 unsigned char uc32[32];
163 };
164 } us_16_32;
165 /* expect+1: error: negative array dimension (-48) [20] */
166 typedef int sizeof_us_16_32[-(int)sizeof(us_16_32)];
167 }
168
169
170 void
171 sizeof_errors(void)
172 {
173 /* expect+1: error: cannot take size/alignment of void [146] */
174 typedef int sizeof_void[-(int)sizeof(void)];
175
176 /*
177 * A 'void array' gets replaced with an 'int array' before
178 * type_size_in_bits gets to see it, thus the 256 * 4 = 1024.
179 */
180 /* expect+2: error: illegal use of 'void' [18] */
181 /* expect+1: error: negative array dimension (-1024) [20] */
182 typedef int sizeof_void_array[-(int)sizeof(void[256])];
183
184 /* expect+1: warning: enum 'incomplete_enum' never defined [235] */
185 enum incomplete_enum;
186 /* expect+2: warning: cannot take size/alignment of incomplete type [143] */
187 /* expect+1: error: negative array dimension (-4) [20] */
188 typedef int sizeof_incomplete_enum[-(int)sizeof(enum incomplete_enum)];
189 }
190
191
192 /*
193 * Due to the 'double' member, the alignment of this struct is 8, so the size
194 * has to be 24 (or at least divisible by 8), otherwise the 'double' member
195 * would not get the correct alignment in an array of this struct.
196 */
197 struct s24 {
198 char c0;
199 double d8;
200 char c16;
201 };
202 /* expect+1: error: negative array dimension (-24) [20] */
203 typedef int sizeof_s24[-(int)sizeof(struct s24)];
204