expr_sizeof.c revision 1.9 1 /* $NetBSD: expr_sizeof.c,v 1.9 2023/06/30 09:21:52 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 void sink(unsigned long);
15
16 struct {
17 int member;
18 } s, *ps;
19
20 /*
21 * In a sizeof expression taking a type name, the type name must be enclosed
22 * in parentheses.
23 */
24 /* expect+1: error: negative array dimension (-4) [20] */
25 typedef int sizeof_int[-(int)sizeof(int)];
26
27 /*
28 * In a sizeof expression taking an expression, the expression may or may not
29 * be enclosed in parentheses, like any other expression.
30 */
31 /* expect+1: error: negative array dimension (-4) [20] */
32 typedef int sizeof_paren_zero[-(int)sizeof(0)];
33 /* expect+1: error: negative array dimension (-4) [20] */
34 typedef int sizeof_zero[-(int)sizeof 0];
35
36 /*
37 * Even though 's' is not a constant expression, 'sizeof s' is.
38 */
39 /* expect+1: error: negative array dimension (-4) [20] */
40 typedef int sizeof_global_var[-(int)sizeof s];
41 /* expect+1: error: negative array dimension (-4) [20] */
42 typedef int sizeof_paren_global_var[-(int)sizeof(s)];
43
44 /*
45 * Even though 'sizeof(s)' may look like a function call expression, the
46 * parentheses around 's' are ordinary parentheses and do not influence the
47 * precedence.
48 *
49 * Therefore, the '.' following the '(s)' takes precedence over the 'sizeof'.
50 * Same for the '->' following the '(ps)'. Same for the '[0]' following the
51 * '(arr)'.
52 */
53 /* expect+1: error: negative array dimension (-4) [20] */
54 typedef int sizeof_paren_global_struct_member[-(int)sizeof(s).member];
55 /* expect+1: error: negative array dimension (-4) [20] */
56 typedef int sizeof_paren_global_ptr_struct_member[-(int)sizeof(ps)->member];
57 int arr[] = { 1, 2, 3 };
58 /* expect+1: error: negative array dimension (-3) [20] */
59 typedef int arr_count[-(int)sizeof(arr) / (int)sizeof(arr)[0]];
60
61 /* FIXME: 'n' is actually used, for the variable length array. */
62 /* expect+2: warning: argument 'n' unused in function 'variable_length_array' [231] */
63 void
64 variable_length_array(int n)
65 {
66 int local_arr[n + 5];
67
68 /*
69 * Since the array length is not constant, it cannot be used in a
70 * typedef. Code like this is already rejected by the compiler. For
71 * simplicity, lint assumes that the array has length 1.
72 */
73 /* expect+1: error: negative array dimension (-4) [20] */
74 typedef int sizeof_local_arr[-(int)sizeof(local_arr)];
75 }
76
77 void
78 bit_fields(void)
79 {
80 struct {
81 _Bool flag0:1;
82 _Bool flag1:1;
83 _Bool flag2:1;
84 } flags;
85 /* expect+1: error: negative array dimension (-1) [20] */
86 typedef int sizeof_flags[-(int)sizeof(flags)];
87
88 struct {
89 struct {
90 _Bool flag0:1;
91 _Bool flag1:1;
92 _Bool flag2:1;
93 };
94 } anonymous_flags;
95 /* FIXME: sizeof must be 1, not 0. */
96 typedef int sizeof_anonymous_flags[-(int)sizeof(anonymous_flags)];
97
98 struct {
99 unsigned int bits0:16;
100 unsigned int bits1:16;
101 } same_storage_unit;
102 /* expect+1: error: negative array dimension (-4) [20] */
103 typedef int sizeof_same_storage_unit[-(int)sizeof(same_storage_unit)];
104
105 // Detect whether a bit-field can span multiple storage units.
106 // If so, the size is 12, if not, the size is 16.
107 struct {
108 unsigned int bits0:24;
109 unsigned int bits1:24;
110 unsigned int bits2:24;
111 unsigned int bits3:24;
112 } cross_storage_unit;
113 /* expect+1: error: negative array dimension (-16) [20] */
114 typedef int sizeof_cross_storage_unit[-(int)sizeof(cross_storage_unit)];
115
116 /*
117 * The bit-fields in a struct may be merged into the same storage
118 * units, even if their types differ. GCC 10, Clang 15 and lint all
119 * agree in packing the first group of bit-fields and the char into
120 * 4 bytes, even though their underlying types differ. The second
121 * group of bit-fields gets its own storage unit.
122 */
123 struct mixed {
124 _Bool flag0:1;
125 signed int signed0:1;
126 unsigned int unsigned0:1;
127 char ch[3];
128 _Bool flag1:1;
129 signed int signed1:1;
130 unsigned int unsigned1:1;
131 } mixed;
132 /* expect+1: error: negative array dimension (-8) [20] */
133 typedef int sizeof_mixed[-(int)sizeof(mixed)];
134 /* FIXME: Implement build_offsetof correctly. */
135 /* expect+3: error: negative array dimension (-8) [20] */
136 typedef int offsetof_mixed_ch[
137 -(int)__builtin_offsetof(struct mixed, ch)
138 ];
139 }
140
141 /*
142 * Ensure that anonymous structs and unions are handled correctly. They were
143 * added in C11, and lint did not properly support them until 2023.
144 */
145 void
146 anonymous_struct_and_union(void)
147 {
148 struct {
149 union {
150 unsigned char uc16[16];
151 unsigned char uc32[32];
152 };
153 } su_16_32;
154 /* FIXME: Must be 32, not 48. */
155 /* expect+1: error: negative array dimension (-48) [20] */
156 typedef int sizeof_su_16_32[-(int)sizeof(su_16_32)];
157
158 union {
159 struct {
160 unsigned char uc16[16];
161 unsigned char uc32[32];
162 };
163 } us_16_32;
164 /* expect+1: error: negative array dimension (-48) [20] */
165 typedef int sizeof_us_16_32[-(int)sizeof(us_16_32)];
166 }
167