@@ -229,23 +229,30 @@ fn exprs_with_muldiv_binop_peeled<'e>(expr: &'e Expr<'_>) -> Vec<&'e Expr<'e>> {
229
229
// For binary operators which both contribute to the sign of the result,
230
230
// collect all their operands, recursively. This ignores overflow.
231
231
ControlFlow :: Continue ( Descend :: Yes )
232
- } else if matches ! ( op. node, BinOpKind :: Rem ) {
232
+ } else if matches ! ( op. node, BinOpKind :: Rem | BinOpKind :: Shr ) {
233
233
// For binary operators where the left hand side determines the sign of the result,
234
234
// only collect that side, recursively. Overflow panics, so this always holds.
235
235
//
236
+ // Large left shifts turn negatives into zeroes, so we can't use it here.
237
+ //
236
238
// > Given remainder = dividend % divisor, the remainder will have the same sign as the dividend
239
+ // > ...
240
+ // > Arithmetic right shift on signed integer types
237
241
// https://doc.rust-lang.org/reference/expressions/operator-expr.html#arithmetic-and-logical-binary-operators
242
+
243
+ // We want to descend into the lhs, but skip the rhs.
244
+ // That's tricky to do using for_each_expr(), so we just keep the lhs intact.
238
245
res. push ( lhs) ;
239
- ControlFlow :: Break ( ( ) )
246
+ ControlFlow :: Continue ( Descend :: No )
240
247
} else {
241
248
// The sign of the result of other binary operators depends on the values of the operands,
242
249
// so try to evaluate the expression.
243
- res. push ( expr ) ;
250
+ res. push ( sub_expr ) ;
244
251
ControlFlow :: Continue ( Descend :: No )
245
252
}
246
253
} else {
247
254
// For other expressions, including unary operators and constants, try to evaluate the expression.
248
- res. push ( expr ) ;
255
+ res. push ( sub_expr ) ;
249
256
ControlFlow :: Continue ( Descend :: No )
250
257
}
251
258
} ) ;
0 commit comments