mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-21 17:52:12 +03:00
Fix ICE in swap_binop() (#16659)
Make `swap_binop()` a method of `HirEqInterExpr`, and use the proper typeck to check the type of an expression. changelog: none (fix of a regression, should be backported) Fixes rust-lang/rust-clippy#16505 <!-- TRIAGEBOT_START --> <!-- TRIAGEBOT_SUMMARY_START --> ### Summary Notes - [Beta-nomination](https://github.com/rust-lang/rust-clippy/pull/16659#issuecomment-3993931812) by [samueltardieu](https://github.com/samueltardieu) *Managed by `@rustbot`—see [help](https://forge.rust-lang.org/triagebot/note.html) for details* <!-- TRIAGEBOT_SUMMARY_END --> <!-- TRIAGEBOT_END -->
This commit is contained in:
@@ -505,7 +505,7 @@ pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool {
|
||||
(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 @@ fn check_ctxt(&mut self, left: SyntaxContext, right: SyntaxContext) -> bool {
|
||||
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<X>(l: Option<&X>, r: Option<&X>, mut eq_fn: impl FnMut(&X, &X) -> bool) -> bool {
|
||||
|
||||
@@ -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)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user