xref: /netbsd-src/tests/usr.bin/xlint/lint1/msg_160.c (revision b2baa50111d645353fa30b4deab0f79d93650c8c)
1*b2baa501Srillig /*	$NetBSD: msg_160.c,v 1.10 2023/03/28 14:44:35 rillig Exp $	*/
2a0a15c14Srillig # 3 "msg_160.c"
3a0a15c14Srillig 
4a0a15c14Srillig // Test for message: operator '==' found where '=' was expected [160]
5a0a15c14Srillig 
6*b2baa501Srillig /* lint1-extra-flags: -h -X 351 */
7232122fbSrillig 
8232122fbSrillig _Bool
both_equal_or_unequal(int a,int b,int c,int d)9232122fbSrillig both_equal_or_unequal(int a, int b, int c, int d)
10232122fbSrillig {
11c4973480Srillig 	/*
12c4973480Srillig 	 * Before tree.c 1.201 from 2021-01-31, lint warned about each of
13c4973480Srillig 	 * the '==' subexpressions even though there is nothing surprising
14c4973480Srillig 	 * about them.
15c4973480Srillig 	 */
16c4973480Srillig 	return (a == b) == (c == d);
17232122fbSrillig }
189ff24546Srillig 
199ff24546Srillig void
209ff24546Srillig eval(_Bool);
219ff24546Srillig 
229ff24546Srillig void
unparenthesized(int a,int b,int c,_Bool z)239ff24546Srillig unparenthesized(int a, int b, int c, _Bool z)
249ff24546Srillig {
259ff24546Srillig 	/*
269ff24546Srillig 	 * This one might be legitimate since the second '==' has _Bool
279ff24546Srillig 	 * on both sides.  Parenthesizing its left-hand operand doesn't
289ff24546Srillig 	 * hurt though.
299ff24546Srillig 	 */
3065e5c21bSrillig 	/* expect+1: warning: operator '==' found where '=' was expected [160] */
3165e5c21bSrillig 	eval(a == b == z);
329ff24546Srillig 
33c4973480Srillig 	/*
34c4973480Srillig 	 * Before tree.c 1.201 from 2021-01-31, lint warned about the
35c4973480Srillig 	 * parenthesized '==' subexpression even though there is nothing
36c4973480Srillig 	 * surprising about it.
37c4973480Srillig 	 */
38c4973480Srillig 	eval((a == b) == z);
399ff24546Srillig 
409ff24546Srillig 	/*
419ff24546Srillig 	 * This one is definitely wrong.  C, unlike Python, does not chain
429ff24546Srillig 	 * comparison operators in the way mathematicians are used to.
439ff24546Srillig 	 */
4465e5c21bSrillig 	/* expect+1: warning: operator '==' found where '=' was expected [160] */
4565e5c21bSrillig 	eval(a == b == c);
469ff24546Srillig 
479ff24546Srillig 	/* Parenthesizing one of the operands makes it obvious enough. */
48c4973480Srillig 	/*
49c4973480Srillig 	 * Before tree.c 1.201 from 2021-01-31, lint warned about the
50c4973480Srillig 	 * parenthesized '==' subexpression even though there is nothing
51c4973480Srillig 	 * surprising about it.
52c4973480Srillig 	 */
53c4973480Srillig 	eval((a == b) == c);
54c4973480Srillig 	/*
55c4973480Srillig 	 * Before tree.c 1.201 from 2021-01-31, lint warned about the
56c4973480Srillig 	 * parenthesized '==' subexpression even though there is nothing
57c4973480Srillig 	 * surprising about it.
58c4973480Srillig 	 */
59c4973480Srillig 	eval(a == (b == c));
609ff24546Srillig }
6189658c8cSrillig 
6289658c8cSrillig void
assignment_in_comma_expression(int len)63afeba29bSrillig assignment_in_comma_expression(int len)
6489658c8cSrillig {
6589658c8cSrillig 
66afeba29bSrillig 	/*
67afeba29bSrillig 	 * No extra parentheses, just a comma operator.
68afeba29bSrillig 	 *
69afeba29bSrillig 	 * The usual interpretation is that the left-hand operand of the
70afeba29bSrillig 	 * comma is a preparation, most often an assignment, and the
71afeba29bSrillig 	 * right-hand operand of the comma is the actual condition.
72afeba29bSrillig 	 */
73afeba29bSrillig 	if (len = 3 * len + 1, len == 0)
74afeba29bSrillig 		return;
75afeba29bSrillig 
76afeba29bSrillig 	/* Seen in bin/csh/dir.c 1.35 from 2020-08-09, line 223. */
77afeba29bSrillig 	/*
78afeba29bSrillig 	 * The extra parentheses are typically used to inform the compiler
79afeba29bSrillig 	 * that an assignment using '=' is intentional, in particular it is
80afeba29bSrillig 	 * not a typo of the comparison operator '=='.
81afeba29bSrillig 	 *
82afeba29bSrillig 	 * The comma operator in a condition is seldom used, which makes it
83afeba29bSrillig 	 * reasonable to assume that the code author selected the operators
84afeba29bSrillig 	 * on purpose.
85afeba29bSrillig 	 *
86afeba29bSrillig 	 * In this case the parentheses are redundant, it's quite possible
87afeba29bSrillig 	 * that they come from a macro expansion though.
88afeba29bSrillig 	 */
89afeba29bSrillig 	if ((len = 3 * len + 1, len == 0))
90afeba29bSrillig 		return;
91afeba29bSrillig 
92afeba29bSrillig 	/*
93afeba29bSrillig 	 * If the comma expression is part of a larger expression, the
94afeba29bSrillig 	 * parentheses are required to mark the operator precedence.  The
95afeba29bSrillig 	 * parentheses must therefore not be interpreted as changing the
96afeba29bSrillig 	 * intention from a condition to an assignment.
97afeba29bSrillig 	 */
98afeba29bSrillig 	if ((len = 3 * len + 1, len == 0) && len < 2)
9989658c8cSrillig 		return;
10089658c8cSrillig }
101