Home | History | Annotate | Line # | Download | only in lint1
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