Skip to content

Commit

Permalink
[const-prop] Support propagating into Assert's cond Operand
Browse files Browse the repository at this point in the history
  • Loading branch information
wesleywiser committed May 19, 2019
1 parent 6afcb56 commit 8e99c76
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 69 deletions.
146 changes: 79 additions & 67 deletions src/librustc_mir/transform/const_prop.rs
Expand Up @@ -656,75 +656,87 @@ impl<'b, 'a, 'tcx> MutVisitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
location: Location,
) {
self.super_terminator(terminator, location);
let source_info = terminator.source_info;;
if let TerminatorKind::Assert { expected, msg, cond, .. } = &terminator.kind {
if let Some(value) = self.eval_operand(&cond, source_info) {
trace!("assertion on {:?} should be {:?}", value, expected);
let expected = ScalarMaybeUndef::from(Scalar::from_bool(*expected));
if expected != self.ecx.read_scalar(value).unwrap() {
// poison all places this operand references so that further code
// doesn't use the invalid value
match cond {
Operand::Move(ref place) | Operand::Copy(ref place) => {
let mut place = place;
while let Place::Projection(ref proj) = *place {
place = &proj.base;
}
if let Place::Base(PlaceBase::Local(local)) = *place {
self.places[local] = None;
}
},
Operand::Constant(_) => {}
let source_info = terminator.source_info;
match &mut terminator.kind {
TerminatorKind::Assert { expected, msg, ref mut cond, .. } => {
if let Some(value) = self.eval_operand(&cond, source_info) {
trace!("assertion on {:?} should be {:?}", value, expected);
let expected = ScalarMaybeUndef::from(Scalar::from_bool(*expected));
let value_const = self.ecx.read_scalar(value).unwrap();
if expected != value_const {
// poison all places this operand references so that further code
// doesn't use the invalid value
match cond {
Operand::Move(ref place) | Operand::Copy(ref place) => {
let mut place = place;
while let Place::Projection(ref proj) = *place {
place = &proj.base;
}
if let Place::Base(PlaceBase::Local(local)) = *place {
self.places[local] = None;
}
},
Operand::Constant(_) => {}
}
let span = terminator.source_info.span;
let hir_id = self
.tcx
.hir()
.as_local_hir_id(self.source.def_id())
.expect("some part of a failing const eval must be local");
use rustc::mir::interpret::InterpError::*;
let msg = match msg {
Overflow(_) |
OverflowNeg |
DivisionByZero |
RemainderByZero => msg.description().to_owned(),
BoundsCheck { ref len, ref index } => {
let len = self
.eval_operand(len, source_info)
.expect("len must be const");
let len = match self.ecx.read_scalar(len) {
Ok(ScalarMaybeUndef::Scalar(Scalar::Bits {
bits, ..
})) => bits,
other => bug!("const len not primitive: {:?}", other),
};
let index = self
.eval_operand(index, source_info)
.expect("index must be const");
let index = match self.ecx.read_scalar(index) {
Ok(ScalarMaybeUndef::Scalar(Scalar::Bits {
bits, ..
})) => bits,
other => bug!("const index not primitive: {:?}", other),
};
format!(
"index out of bounds: \
the len is {} but the index is {}",
len,
index,
)
},
// Need proper const propagator for these
_ => return,
};
self.tcx.lint_hir(
::rustc::lint::builtin::CONST_ERR,
hir_id,
span,
&msg,
);
} else {
if let ScalarMaybeUndef::Scalar(scalar) = value_const {
*cond = self.operand_from_scalar(
scalar,
self.tcx.types.bool,
source_info.span,
);
}
}
let span = terminator.source_info.span;
let hir_id = self
.tcx
.hir()
.as_local_hir_id(self.source.def_id())
.expect("some part of a failing const eval must be local");
use rustc::mir::interpret::InterpError::*;
let msg = match msg {
Overflow(_) |
OverflowNeg |
DivisionByZero |
RemainderByZero => msg.description().to_owned(),
BoundsCheck { ref len, ref index } => {
let len = self
.eval_operand(len, source_info)
.expect("len must be const");
let len = match self.ecx.read_scalar(len) {
Ok(ScalarMaybeUndef::Scalar(Scalar::Bits {
bits, ..
})) => bits,
other => bug!("const len not primitive: {:?}", other),
};
let index = self
.eval_operand(index, source_info)
.expect("index must be const");
let index = match self.ecx.read_scalar(index) {
Ok(ScalarMaybeUndef::Scalar(Scalar::Bits {
bits, ..
})) => bits,
other => bug!("const index not primitive: {:?}", other),
};
format!(
"index out of bounds: \
the len is {} but the index is {}",
len,
index,
)
},
// Need proper const propagator for these
_ => return,
};
self.tcx.lint_hir(
::rustc::lint::builtin::CONST_ERR,
hir_id,
span,
&msg,
);
}
}
},
_ => {}
}
}
}
2 changes: 1 addition & 1 deletion src/test/mir-opt/const_prop/array_index.rs
Expand Up @@ -23,7 +23,7 @@ fn main() {
// bb0: {
// ...
// _5 = const true;
// assert(move _5, "index out of bounds: the len is move _4 but the index is _3") -> bb1;
// assert(const true, "index out of bounds: the len is move _4 but the index is _3") -> bb1;
// }
// bb1: {
// _1 = _2[_3];
Expand Down
2 changes: 1 addition & 1 deletion src/test/mir-opt/const_prop/checked_add.rs
Expand Up @@ -16,6 +16,6 @@ fn main() {
// bb0: {
// ...
// _2 = (const 2u32, const false);
// assert(!move (_2.1: bool), "attempt to add with overflow") -> bb1;
// assert(!const false, "attempt to add with overflow") -> bb1;
// }
// END rustc.main.ConstProp.after.mir

0 comments on commit 8e99c76

Please sign in to comment.