1/* $NetBSD: expr_sizeof.c,v 1.18 2024/05/03 19:16:13 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 15void sink(unsigned long); 16 17struct { 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] */ 26typedef 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] */ 33typedef int sizeof_paren_zero[-(int)sizeof(0)]; 34/* expect+1: error: negative array dimension (-4) [20] */ 35typedef 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] */ 41typedef int sizeof_global_var[-(int)sizeof s]; 42/* expect+1: error: negative array dimension (-4) [20] */ 43typedef 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] */ 55typedef int sizeof_paren_global_struct_member[-(int)sizeof(s).member]; 56/* expect+1: error: negative array dimension (-4) [20] */ 57typedef int sizeof_paren_global_ptr_struct_member[-(int)sizeof(ps)->member]; 58int arr[] = { 1, 2, 3 }; 59/* expect+1: error: negative array dimension (-3) [20] */ 60typedef 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: parameter 'n' unused in function 'variable_length_array' [231] */ 64void 65variable_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 78void 79bit_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 /* expect+3: error: negative array dimension (-1) [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 */ 145void 146anonymous_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 /* expect+1: error: negative array dimension (-32) [20] */ 155 typedef int sizeof_su_16_32[-(int)sizeof(su_16_32)]; 156 157 union { 158 struct { 159 unsigned char uc16[16]; 160 unsigned char uc32[32]; 161 }; 162 } us_16_32; 163 /* expect+1: error: negative array dimension (-48) [20] */ 164 typedef int sizeof_us_16_32[-(int)sizeof(us_16_32)]; 165} 166 167 168void 169sizeof_errors(void) 170{ 171 /* expect+1: error: cannot take size/alignment of void [146] */ 172 typedef int sizeof_void[-(int)sizeof(void)]; 173 174 /* 175 * A 'void array' gets replaced with an 'int array' before 176 * type_size_in_bits gets to see it, thus the 256 * 4 = 1024. 177 */ 178 /* expect+2: error: illegal use of 'void' [18] */ 179 /* expect+1: error: negative array dimension (-1024) [20] */ 180 typedef int sizeof_void_array[-(int)sizeof(void[256])]; 181 182 /* expect+1: warning: enum 'incomplete_enum' never defined [235] */ 183 enum incomplete_enum; 184 /* expect+2: warning: cannot take size/alignment of incomplete type [143] */ 185 /* expect+1: error: negative array dimension (-4) [20] */ 186 typedef int sizeof_incomplete_enum[-(int)sizeof(enum incomplete_enum)]; 187} 188 189 190/* 191 * Due to the 'double' member, the alignment of this struct is 8, so the size 192 * has to be 24 (or at least divisible by 8), otherwise the 'double' member 193 * would not get the correct alignment in an array of this struct. 194 */ 195struct s24 { 196 char c0; 197 double d8; 198 char c16; 199}; 200/* expect+1: error: negative array dimension (-24) [20] */ 201typedef int sizeof_s24[-(int)sizeof(struct s24)]; 202 203void 204sizeof_array_parameter(short arr[12345]) 205{ 206 // The size of an array parameter is the size of the decayed pointer. 207 // Subtracting 'sizeof(void *)' makes the test platform-independent. 208 typedef int sizeof_arr[-(int)(sizeof arr - sizeof(void *))]; 209 210 // The 2 comes from 'sizeof(short)', as the type 'array[size] of elem' 211 // decays into the type 'pointer to elem', not 'pointer to array[size] 212 // of elem'. 213 /* expect+1: error: negative array dimension (-2) [20] */ 214 typedef int sizeof_arr_elem[-(int)(sizeof *arr)]; 215} 216 217 218void 219sequence_of_structs(void) 220{ 221 typedef unsigned char uint8_t; 222 typedef unsigned short uint16_t; 223 typedef unsigned int uint32_t; 224 typedef unsigned long long uint64_t; 225 226 union fp_addr { 227 uint64_t fa_64; 228 struct { 229 uint32_t fa_off; 230 uint16_t fa_seg; 231 uint16_t fa_opcode; 232 } fa_32; 233 } __packed _Alignas(4); 234 235 struct fpacc87 { 236 uint64_t f87_mantissa; 237 uint16_t f87_exp_sign; 238 } __packed _Alignas(2); 239 240 // FIXME: This otherwise unused struct declaration influences the 241 // offsets checked below. Without this struct, sizeof(struct save87) 242 // is calculated correctly as 108 below. 243 struct fpaccfx { 244 struct fpacc87 r _Alignas(16); 245 }; 246 247 struct save87 { 248 uint16_t s87_cw _Alignas(4); 249 uint16_t s87_sw _Alignas(4); 250 uint16_t s87_tw _Alignas(4); 251 union fp_addr s87_ip; 252 union fp_addr s87_dp; 253 struct fpacc87 s87_ac[8]; 254 }; 255 256 /* expect+1: error: negative array dimension (-20) [20] */ 257 typedef int o1[-(int)((unsigned long)(&(((struct save87 *)0)->s87_dp)))]; 258 // FIXME: must be 28. 259 /* expect+1: error: negative array dimension (-32) [20] */ 260 typedef int o2[-(int)((unsigned long)(&(((struct save87 *)0)->s87_ac)))]; 261 // FIXME: must be 108. 262 /* expect+1: error: negative array dimension (-112) [20] */ 263 typedef int reveal[-(int)sizeof(struct save87)]; 264} 265