-
Notifications
You must be signed in to change notification settings - Fork 12.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Start emitting overflow lints for const promoted SHL & SHRs #119339
Start emitting overflow lints for const promoted SHL & SHRs #119339
Conversation
This fixes the issue where no lints were firing for overflowing SHL and SHR ops. That happened because `ConstPropagator::check_binary_op()`, which is responsible for firing these lints, was skipping them because it couldn't find any `Shl()` or `Shr()` ops in the main MIR. That in turn occurred because our const promotion pass `PromoteTemps` removes these ops from the MIR when it runs. With this change, the firing of these particular lints is predicated on the presence of an assert terminator instead, which fortunately is not removed by `PromoteTemps`
r? @b-naber (rustbot has picked a reviewer for you, use r? to override) |
@rustbot author |
This comment has been minimized.
This comment has been minimized.
// but it can't because they are getting removed from the MIR | ||
// during const promotion. So we check the associated asserts | ||
// here instead as they are not removed by promotion. | ||
(AssertKind::Overflow(*bin_op, eval_to_int(op1), eval_to_int(op2)), true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you emit the lint here then you should be able to remove the shift handling from check_binary_op. That should also fix the duplicate lints.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tried that, but it eliminates only 6 of the 59 new duplicates added by this change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What exactly did you try? I should look something like this:
diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs
index 99eecb567f2..d36798518e2 100644
--- a/compiler/rustc_mir_transform/src/const_prop_lint.rs
+++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs
@@ -317,37 +317,9 @@ fn check_binary_op(
});
let l = self
.use_ecx(location, |this| this.ecx.read_immediate(&this.ecx.eval_operand(left, None)?));
- // Check for exceeding shifts *even if* we cannot evaluate the LHS.
+ // Shifts are linted via the `Assert` terminator, not this function.
if matches!(op, BinOp::Shr | BinOp::Shl) {
- let r = r.clone()?;
- // We need the type of the LHS. We cannot use `place_layout` as that is the type
- // of the result, which for checked binops is not the same!
- let left_ty = left.ty(self.local_decls(), self.tcx);
- let left_size = self.ecx.layout_of(left_ty).ok()?.size;
- let right_size = r.layout.size;
- let r_bits = r.to_scalar().to_bits(right_size).ok();
- if r_bits.is_some_and(|b| b >= left_size.bits() as u128) {
- debug!("check_binary_op: reporting assert for {:?}", location);
- let source_info = self.body().source_info(location);
- let panic = AssertKind::Overflow(
- op,
- match l {
- Some(l) => l.to_const_int(),
- // Invent a dummy value, the diagnostic ignores it anyway
- None => ConstInt::new(
- ScalarInt::try_from_uint(1_u8, left_size).unwrap(),
- left_ty.is_signed(),
- left_ty.is_ptr_sized_integral(),
- ),
- },
- r.to_const_int(),
- );
- self.report_assert_as_lint(
- source_info,
- AssertLint::ArithmeticOverflow(source_info.span, panic),
- );
- return None;
- }
+ return None;
}
if let (Some(l), Some(r)) = (l, r) {
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh. I just got rid of the entire if
block. Didn't realize I must return None
to disable shift handling.
I have done that now in the latest commit I pushed. It has eliminated all duplicates. However, we have the opposite problem now. Many of the shift lints in release builds have been silenced possibly because we don't emit asserts in those builds.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Many of the shift lints in release builds have been silenced possibly because we don't emit asserts in those builds.
Ah... right. Yeah for debug/release consistency we really want to lint on the operation (shl/shr/add/...), not the assert. But then we need to lint in promoteds as well.
The job Click to see the possible cause of the failure (guessed by this bot)
|
☔ The latest upstream changes (presumably #119627) made this pull request unmergeable. Please resolve the merge conflicts. |
I think this got superseded by #119432? |
Yes. I'll abandon it. |
Fixes #117949
The overflow lints for promoted shift ops had been accidently disabled by #108282. That is because #108282 caused
Shl
&Shr
ops to be removed from the MIR which silenced the lints.In this PR we start firing them again by triggering them based on the assert terminators instead which luckily are not removed from the MIR.