Home | History | Annotate | Line # | Download | only in lint1
      1 /*	$NetBSD: msg_129.c,v 1.11 2025/09/17 19:25:23 rillig Exp $	*/
      2 # 3 "msg_129.c"
      3 
      4 // Test for message: expression has null effect [129]
      5 
      6 /* lint1-extra-flags: -h -X 351 */
      7 
      8 typedef unsigned char uint8_t;
      9 typedef unsigned int uint32_t;
     10 
     11 _Bool side_effect(void);
     12 
     13 /*
     14  * Before tree.c 1.198 from 2021-01-30, the nested comma operators were
     15  * wrongly reported as having no side effect.
     16  *
     17  * The bug was that has_side_effect did not properly examine the sub-nodes.
     18  * The ',' operator itself has m_has_side_effect == false since it depends
     19  * on its operands whether the ',' actually has side effects.  For nested ','
     20  * operators, the function did not evaluate the operands deeply but only did
     21  * a quick shallow test on the m_has_side_effect property.  Since that is
     22  * false, lint thought that the whole expression would have no side effect.
     23  */
     24 void
     25 uint8_buffer_write_uint32(uint8_t *c, uint32_t l)
     26 {
     27 	(*(c++) = (uint8_t)(l & 0xff),
     28 	    *(c++) = (uint8_t)((l >> 8L) & 0xff),
     29 	    *(c++) = (uint8_t)((l >> 16L) & 0xff),
     30 	    *(c++) = (uint8_t)((l >> 24L) & 0xff));
     31 }
     32 
     33 void
     34 operator_and(_Bool cond)
     35 {
     36 	cond && side_effect();
     37 	// ... is an abbreviation for ...
     38 	if (cond)
     39 		side_effect();
     40 	// This pattern is much more common in shell or Perl than in C.
     41 
     42 	/* expect+1: warning: expression has null effect [129] */
     43 	side_effect() && cond;
     44 }
     45 
     46 void
     47 operator_or(_Bool cond)
     48 {
     49 	cond || side_effect();
     50 	// ... is an abbreviation for ...
     51 	if (!cond)
     52 		side_effect();
     53 	// This pattern is much more common in shell or Perl than in C.
     54 
     55 	/* expect+1: warning: expression has null effect [129] */
     56 	side_effect() || cond;
     57 }
     58 
     59 void
     60 operator_quest_colon(void)
     61 {
     62 	side_effect() ? side_effect() : side_effect();
     63 
     64 	/* expect+1: warning: expression has null effect [129] */
     65 	side_effect() ? side_effect() : 0;
     66 
     67 	/* expect+1: warning: expression has null effect [129] */
     68 	side_effect() ? 0 : side_effect();
     69 
     70 	/* expect+1: warning: expression has null effect [129] */
     71 	side_effect() ? 0 : 1;
     72 
     73 	0 ? side_effect() : side_effect();
     74 
     75 	/* expect+1: warning: expression has null effect [129] */
     76 	0 ? side_effect() : 0;
     77 
     78 	/* expect+1: warning: expression has null effect [129] */
     79 	0 ? 0 : side_effect();
     80 
     81 	/* expect+1: warning: expression has null effect [129] */
     82 	0 ? 0 : 1;
     83 
     84 	1 ? side_effect() : side_effect();
     85 
     86 	/* expect+1: warning: expression has null effect [129] */
     87 	1 ? side_effect() : 0;
     88 
     89 	/* expect+1: warning: expression has null effect [129] */
     90 	1 ? 0 : side_effect();
     91 
     92 	/* expect+1: warning: expression has null effect [129] */
     93 	1 ? 1 : 0;
     94 
     95 	0 ? (void)1 : (void)0;
     96 }
     97 
     98 void
     99 operator_comma(void)
    100 {
    101 	side_effect(), 0;		/* the 0 is redundant */
    102 	/* expect+1: warning: expression has null effect [129] */
    103 	0, side_effect();
    104 
    105 	if (side_effect(), 0)		/* the 0 controls the 'if' */
    106 		return;
    107 	/* expect+1: warning: expression has null effect [129] */
    108 	if (0, side_effect())
    109 		return;
    110 }
    111 
    112 void
    113 legitimate_use_cases(int arg)
    114 {
    115 	int local = 3;
    116 
    117 	/*
    118 	 * This expression is commonly used to mark the parameter as
    119 	 * deliberately unused.
    120 	 */
    121 	(void)arg;
    122 
    123 	/*
    124 	 * This expression is commonly used to mark the local variable as
    125 	 * deliberately unused.  This situation occurs when the local
    126 	 * variable is only used in some but not all compile-time selectable
    127 	 * variants of the code, such as in debugging mode, and writing down
    128 	 * the exact conditions would complicate the code unnecessarily.
    129 	 */
    130 	(void)local;
    131 
    132 	/* This is a shorthand notation for a do-nothing command. */
    133 	(void)0;
    134 
    135 	/*
    136 	 * At the point where lint checks for expressions having a null
    137 	 * effect, constants have been folded, therefore the following
    138 	 * expression is considered safe as well.  It does not appear in
    139 	 * practice though.
    140 	 */
    141 	(void)(3 - 3);
    142 
    143 	/*
    144 	 * This variant of the do-nothing command is commonly used in
    145 	 * preprocessor macros since it works nicely with if-else and if-then
    146 	 * statements.  It is longer than the above variant, and it is not
    147 	 * embeddable into an expression.
    148 	 */
    149 	do {
    150 	} while (0);
    151 
    152 	/*
    153 	 * Only the expression '(void)0' is common, other expressions are
    154 	 * unusual enough to warrant a warning.
    155 	 */
    156 	/* expect+1: warning: expression has null effect [129] */
    157 	(void)13;
    158 
    159 	/* Double casts are unusual enough to warrant a warning. */
    160 	/* expect+1: warning: expression has null effect [129] */
    161 	(void)(void)0;
    162 }
    163 
    164 int
    165 return_statement_expression(int arg)
    166 {
    167 	({
    168 		int local = arg;
    169 		local + 4;
    170 	/* expect+1: warning: expression has null effect [129] */
    171 	});
    172 
    173 	if (arg == 1)
    174 		return ({
    175 			int local = arg;
    176 			// Before cgram.y 1.513 from 2024-10-29, lint wrongly
    177 			// warned that this expression would have a null effect.
    178 			local;
    179 		});
    180 
    181 	if (arg == 2)
    182 		return ({
    183 			int local = arg;
    184 			// Before cgram.y 1.513 from 2024-10-29, lint wrongly
    185 			// warned that this expression would have a null effect.
    186 			local + 4;
    187 		});
    188 
    189 	return 0;
    190 }
    191