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