mirror of
https://github.com/rust-lang/rust.git
synced 2025-04-28 02:57:37 +00:00
[const-prop] Support propagating into Assert's cond
Operand
This commit is contained in:
parent
6afcb56285
commit
8e99c76089
@ -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,
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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];
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user