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