/* $NetBSD: msg_169.c,v 1.10 2024/12/15 06:04:17 rillig Exp $ */ # 3 "msg_169.c" // Test for message: possible precedence confusion between '%s' and '%s' [169] /* lint1-flags: -g -h -S -w -X 191,351 */ typedef _Bool bool; void confusing_shift_arith(unsigned a, unsigned b, unsigned c, unsigned char ch) { unsigned con, okl, okr; /* expect+1: warning: possible precedence confusion between '<<' and '+' [169] */ con = a + b << c; okl = (a + b) << c; okr = a + (b << c); /* expect+1: warning: possible precedence confusion between '<<' and '+' [169] */ con = a << b + c; okl = (a << b) + c; okr = a << (b + c); /* expect+1: warning: possible precedence confusion between '>>' and '-' [169] */ con = a - b >> c; okl = (a - b) >> c; okr = a - (b >> c); /* expect+1: warning: possible precedence confusion between '>>' and '-' [169] */ con = a >> b - c; okl = (a >> b) - c; okr = a >> (b - c); // Parenthesizing the inner operands has no effect on the warning. /* expect+1: warning: possible precedence confusion between '<<' and '+' [169] */ con = (a) + b << c; /* expect+1: warning: possible precedence confusion between '<<' and '+' [169] */ con = a + (b) << c; /* expect+1: warning: possible precedence confusion between '<<' and '+' [169] */ con = a + b << (c); // The usual arithmetic promotions have no effect on the warning. /* expect+1: warning: possible precedence confusion between '<<' and '+' [169] */ con = ch + b << c; /* expect+1: warning: possible precedence confusion between '<<' and '+' [169] */ con = a + ch << c; /* expect+1: warning: possible precedence confusion between '<<' and '+' [169] */ con = a + b << ch; } void confusing_logical(bool a, bool b, bool c, bool d) { bool con, okl, okr, okb, eql; eql = a && b && c; eql = a || b || c; /* expect+1: warning: possible precedence confusion between '||' and '&&' [169] */ con = a && b || c; okl = (a && b) || c; okr = a && (b || c); /* expect+1: warning: possible precedence confusion between '||' and '&&' [169] */ con = a || b && c; okl = (a || b) && c; okr = a || (b && c); // When both nested operands have confusing precedence, there's only // a single warning, as that is enough to point to the issue. /* expect+1: warning: possible precedence confusion between '||' and '&&' [169] */ con = a && b || c && d; /* expect+1: warning: possible precedence confusion between '||' and '&&' [169] */ okl = (a && b) || c && d; /* expect+1: warning: possible precedence confusion between '||' and '&&' [169] */ okr = a && b || (c && d); okb = (a && b) || (c && d); } void confusing_bitwise(unsigned a, unsigned b, unsigned c) { bool con, okl, okr, eql; eql = a & b & c; eql = a | b | c; eql = a ^ b ^ c; /* expect+1: warning: possible precedence confusion between '|' and '^' [169] */ con = a | b ^ c; okl = (a | b) ^ c; okr = a | (b ^ c); /* expect+1: warning: possible precedence confusion between '|' and '&' [169] */ con = a | b & c; okl = (a | b) & c; okr = a | (b & c); /* expect+1: warning: possible precedence confusion between '|' and '^' [169] */ con = a ^ b | c; okl = (a ^ b) | c; okr = a ^ (b | c); /* expect+1: warning: possible precedence confusion between '^' and '&' [169] */ con = a ^ b & c; okl = (a ^ b) & c; okr = a ^ (b & c); /* expect+1: warning: possible precedence confusion between '|' and '&' [169] */ con = a & b | c; okl = (a & b) ^ c; okr = a & (b ^ c); /* expect+1: warning: possible precedence confusion between '^' and '&' [169] */ con = a & b ^ c; okl = (a & b) ^ c; okr = a & (b ^ c); /* expect+1: warning: possible precedence confusion between '&' and '+' [169] */ con = a & b + c; okl = (a & b) + c; okr = a & (b + c); /* expect+1: warning: possible precedence confusion between '|' and '-' [169] */ con = a - b | c; okl = (a - b) | c; okr = a - (b | c); // This looks like a binomial formula but isn't. /* expect+1: warning: possible precedence confusion between '^' and '+' [169] */ con = a ^ 2 - 2 * a * b + b ^ 2; // This isn't a binomial formula either since '^' means xor. con = (a ^ 2) - 2 * a * b + (b ^ 2); } void constant_expressions(void) { unsigned con; // The check for confusing precedence happens after constant folding. // Therefore the following lines do not generate warnings. con = 1 & 2 | 3; con = 4 << 5 + 6; con = 7 ^ 8 & 9; } void cast_expressions(char a, char b, char c) { unsigned con; // Adding casts to the leaf nodes doesn't change anything about the // confusing precedence. /* expect+1: warning: possible precedence confusion between '|' and '&' [169] */ con = (unsigned)a | (unsigned)b & (unsigned)c; /* expect+1: warning: possible precedence confusion between '|' and '&' [169] */ con = (unsigned)a & (unsigned)b | (unsigned)c; // Adding a cast around the whole calculation doesn't change the // precedence as well. /* expect+1: warning: possible precedence confusion between '|' and '&' [169] */ con = (unsigned)(a | b & c); // Adding a cast around an intermediate result groups the operands // of the main node, which prevents any confusion about precedence. con = (unsigned)a | (unsigned)(b & c); con = a | (unsigned)(b & c); con = (unsigned)(a | b) & (unsigned)c; con = (unsigned)(a | b) & c; } void expected_precedence(int a, int b, int c) { int ok; ok = a + b * c; } void implicit_conversion_to_long(long la, int a) { int ok; /* expect+1: warning: possible precedence confusion between '|' and '&' [169] */ ok = a & a | la; /* * Before tree.c 1.132 from 2021-01-04, there was a typo in * check_precedence_confusion that prevented the right-hand operand * from being flagged as possibly confusing if there was an implicit * conversion or an explicit cast between the main operator ('|') and * the nested operator ('&'). */ /* expect+1: warning: possible precedence confusion between '|' and '&' [169] */ ok = la | a & a; ok = (a & a) | la; /* always ok */ ok = la | (a & a); /* always ok */ /* * Before tree.c 1.132, this expression didn't generate a warning * because the right-hand operand was CVT, and there is no confusing * precedence between BITOR and CVT. * * Since tree.c 1.132, this expression doesn't generate a warning * because the right-hand operand is parenthesized. There is no way * to have the right operand casted and at the same time not * parenthesized since the cast operator has higher precedence. * * In summary, there is no visible change, but the implementation is * now works as intended. */ ok = la | (int)(a & a); /* always ok */ }