diff --git a/clippy_utils/src/hir_utils.rs b/clippy_utils/src/hir_utils.rs index abc6885bef2d..9d5a1fe8ca88 100644 --- a/clippy_utils/src/hir_utils.rs +++ b/clippy_utils/src/hir_utils.rs @@ -505,7 +505,7 @@ impl HirEqInterExpr<'_, '_, '_> { (ExprKind::Block(l, _), ExprKind::Block(r, _)) => self.eq_block(l, r), (ExprKind::Binary(l_op, ll, lr), ExprKind::Binary(r_op, rl, rr)) => { l_op.node == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr) - || swap_binop(self.inner.cx, l_op.node, ll, lr).is_some_and(|(l_op, ll, lr)| { + || self.swap_binop(l_op.node, ll, lr).is_some_and(|(l_op, ll, lr)| { l_op == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr) }) }, @@ -921,6 +921,40 @@ impl HirEqInterExpr<'_, '_, '_> { self.right_ctxt = right; true } + + fn swap_binop<'a>( + &self, + binop: BinOpKind, + lhs: &'a Expr<'a>, + rhs: &'a Expr<'a>, + ) -> Option<(BinOpKind, &'a Expr<'a>, &'a Expr<'a>)> { + match binop { + // `==` and `!=`, are commutative + BinOpKind::Eq | BinOpKind::Ne => Some((binop, rhs, lhs)), + // Comparisons can be reversed + BinOpKind::Lt => Some((BinOpKind::Gt, rhs, lhs)), + BinOpKind::Le => Some((BinOpKind::Ge, rhs, lhs)), + BinOpKind::Ge => Some((BinOpKind::Le, rhs, lhs)), + BinOpKind::Gt => Some((BinOpKind::Lt, rhs, lhs)), + // Non-commutative operators + BinOpKind::Shl | BinOpKind::Shr | BinOpKind::Rem | BinOpKind::Sub | BinOpKind::Div => None, + // We know that those operators are commutative for primitive types, + // and we don't assume anything for other types + BinOpKind::Mul + | BinOpKind::Add + | BinOpKind::And + | BinOpKind::Or + | BinOpKind::BitAnd + | BinOpKind::BitXor + | BinOpKind::BitOr => self.inner.maybe_typeck_results.and_then(|(typeck_lhs, _)| { + typeck_lhs + .expr_ty_adjusted(lhs) + .peel_refs() + .is_primitive() + .then_some((binop, rhs, lhs)) + }), + } + } } /// Some simple reductions like `{ return }` => `return` @@ -966,39 +1000,6 @@ fn reduce_exprkind<'hir>(cx: &LateContext<'_>, kind: &'hir ExprKind<'hir>) -> &' } } -fn swap_binop<'a>( - cx: &LateContext<'_>, - binop: BinOpKind, - lhs: &'a Expr<'a>, - rhs: &'a Expr<'a>, -) -> Option<(BinOpKind, &'a Expr<'a>, &'a Expr<'a>)> { - match binop { - // `==` and `!=`, are commutative - BinOpKind::Eq | BinOpKind::Ne => Some((binop, rhs, lhs)), - // Comparisons can be reversed - BinOpKind::Lt => Some((BinOpKind::Gt, rhs, lhs)), - BinOpKind::Le => Some((BinOpKind::Ge, rhs, lhs)), - BinOpKind::Ge => Some((BinOpKind::Le, rhs, lhs)), - BinOpKind::Gt => Some((BinOpKind::Lt, rhs, lhs)), - // Non-commutative operators - BinOpKind::Shl | BinOpKind::Shr | BinOpKind::Rem | BinOpKind::Sub | BinOpKind::Div => None, - // We know that those operators are commutative for primitive types, - // and we don't assume anything for other types - BinOpKind::Mul - | BinOpKind::Add - | BinOpKind::And - | BinOpKind::Or - | BinOpKind::BitAnd - | BinOpKind::BitXor - | BinOpKind::BitOr => cx - .typeck_results() - .expr_ty_adjusted(lhs) - .peel_refs() - .is_primitive() - .then_some((binop, rhs, lhs)), - } -} - /// Checks if the two `Option`s are both `None` or some equal values as per /// `eq_fn`. pub fn both(l: Option<&X>, r: Option<&X>, mut eq_fn: impl FnMut(&X, &X) -> bool) -> bool { diff --git a/tests/ui/if_same_then_else.rs b/tests/ui/if_same_then_else.rs index 6e0e2c5ea720..6982a9d143e4 100644 --- a/tests/ui/if_same_then_else.rs +++ b/tests/ui/if_same_then_else.rs @@ -305,3 +305,20 @@ fn issue16416_prim(x: bool, a: u32, b: u32) { //~v if_same_then_else _ = if x { a >= b } else { b <= a }; } + +mod issue16505 { + macro_rules! foo { + (< $hi:literal : $lo:literal > | $N:tt bits) => {{ + const NEW_N_: usize = $hi - $lo + 1; + NEW_N_ + }}; + } + + fn bar(x: bool) { + _ = if x { + foo!(<2:0> | 3 bits) == foo!(<3:1> | 3 bits) + } else { + foo!(<3:1> | 3 bits) == foo!(<2:0> | 3 bits) + }; + } +}