Skip to content

Commit

Permalink
Rollup merge of #91786 - tmiasko:const-prop, r=oli-obk
Browse files Browse the repository at this point in the history
Return an error when `eval_rvalue_with_identities` fails

Previously some code paths would fail to evaluate the rvalue, while
incorrectly indicating success with `Ok`. As a result the previous value
of lhs could have been incorrectly const propagated.

Fixes #91725.

r? `@oli-obk`
  • Loading branch information
matthiaskrgr authored Dec 14, 2021
2 parents f608e51 + ffe067c commit a38d668
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 52 deletions.
86 changes: 34 additions & 52 deletions compiler/rustc_mir_transform/src/const_prop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -752,62 +752,44 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
rvalue: &Rvalue<'tcx>,
place: Place<'tcx>,
) -> Option<()> {
self.use_ecx(|this| {
match rvalue {
Rvalue::BinaryOp(op, box (left, right))
| Rvalue::CheckedBinaryOp(op, box (left, right)) => {
let l = this.ecx.eval_operand(left, None);
let r = this.ecx.eval_operand(right, None);

let const_arg = match (l, r) {
(Ok(ref x), Err(_)) | (Err(_), Ok(ref x)) => this.ecx.read_immediate(x)?,
(Err(e), Err(_)) => return Err(e),
(Ok(_), Ok(_)) => {
this.ecx.eval_rvalue_into_place(rvalue, place)?;
return Ok(());
}
};

let arg_value = const_arg.to_scalar()?.to_bits(const_arg.layout.size)?;
let dest = this.ecx.eval_place(place)?;

match op {
BinOp::BitAnd => {
if arg_value == 0 {
this.ecx.write_immediate(*const_arg, &dest)?;
}
}
BinOp::BitOr => {
if arg_value == const_arg.layout.size.truncate(u128::MAX)
|| (const_arg.layout.ty.is_bool() && arg_value == 1)
{
this.ecx.write_immediate(*const_arg, &dest)?;
}
}
BinOp::Mul => {
if const_arg.layout.ty.is_integral() && arg_value == 0 {
if let Rvalue::CheckedBinaryOp(_, _) = rvalue {
let val = Immediate::ScalarPair(
const_arg.to_scalar()?.into(),
Scalar::from_bool(false).into(),
);
this.ecx.write_immediate(val, &dest)?;
} else {
this.ecx.write_immediate(*const_arg, &dest)?;
}
}
}
_ => {
this.ecx.eval_rvalue_into_place(rvalue, place)?;
self.use_ecx(|this| match rvalue {
Rvalue::BinaryOp(op, box (left, right))
| Rvalue::CheckedBinaryOp(op, box (left, right)) => {
let l = this.ecx.eval_operand(left, None);
let r = this.ecx.eval_operand(right, None);

let const_arg = match (l, r) {
(Ok(ref x), Err(_)) | (Err(_), Ok(ref x)) => this.ecx.read_immediate(x)?,
(Err(e), Err(_)) => return Err(e),
(Ok(_), Ok(_)) => return this.ecx.eval_rvalue_into_place(rvalue, place),
};

let arg_value = const_arg.to_scalar()?.to_bits(const_arg.layout.size)?;
let dest = this.ecx.eval_place(place)?;

match op {
BinOp::BitAnd if arg_value == 0 => this.ecx.write_immediate(*const_arg, &dest),
BinOp::BitOr
if arg_value == const_arg.layout.size.truncate(u128::MAX)
|| (const_arg.layout.ty.is_bool() && arg_value == 1) =>
{
this.ecx.write_immediate(*const_arg, &dest)
}
BinOp::Mul if const_arg.layout.ty.is_integral() && arg_value == 0 => {
if let Rvalue::CheckedBinaryOp(_, _) = rvalue {
let val = Immediate::ScalarPair(
const_arg.to_scalar()?.into(),
Scalar::from_bool(false).into(),
);
this.ecx.write_immediate(val, &dest)
} else {
this.ecx.write_immediate(*const_arg, &dest)
}
}
}
_ => {
this.ecx.eval_rvalue_into_place(rvalue, place)?;
_ => this.ecx.eval_rvalue_into_place(rvalue, place),
}
}

Ok(())
_ => this.ecx.eval_rvalue_into_place(rvalue, place),
})
}

Expand Down
12 changes: 12 additions & 0 deletions src/test/ui/mir/mir_const_prop_identity.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Regression test for issue #91725.
//
// run-pass
// compile-flags: -Zmir-opt-level=4

fn main() {
let a = true;
let _ = &a;
let mut b = false;
b |= a;
assert!(b);
}

0 comments on commit a38d668

Please sign in to comment.