Skip to content

Commit eea75dc

Browse files
committed
[const-prop] Support propagating into Assert's cond Operand
1 parent ba7b831 commit eea75dc

File tree

3 files changed

+77
-69
lines changed

3 files changed

+77
-69
lines changed

src/librustc_mir/transform/const_prop.rs

+75-67
Original file line numberDiff line numberDiff line change
@@ -649,75 +649,83 @@ impl<'b, 'a, 'tcx> MutVisitor<'tcx> for ConstPropagator<'b, 'a, 'tcx> {
649649
location: Location,
650650
) {
651651
self.super_terminator(terminator, location);
652-
let source_info = terminator.source_info;;
653-
if let TerminatorKind::Assert { expected, msg, cond, .. } = &terminator.kind {
654-
if let Some(value) = self.eval_operand(&cond, source_info) {
655-
trace!("assertion on {:?} should be {:?}", value, expected);
656-
let expected = ScalarMaybeUndef::from(Scalar::from_bool(*expected));
657-
if expected != self.ecx.read_scalar(value).unwrap() {
658-
// poison all places this operand references so that further code
659-
// doesn't use the invalid value
660-
match cond {
661-
Operand::Move(ref place) | Operand::Copy(ref place) => {
662-
let mut place = place;
663-
while let Place::Projection(ref proj) = *place {
664-
place = &proj.base;
665-
}
666-
if let Place::Base(PlaceBase::Local(local)) = *place {
667-
self.places[local] = None;
668-
}
669-
},
670-
Operand::Constant(_) => {}
652+
let source_info = terminator.source_info;
653+
match &mut terminator.kind {
654+
TerminatorKind::Assert { expected, msg, ref mut cond, .. } => {
655+
if let Some(value) = self.eval_operand(&cond, source_info) {
656+
trace!("assertion on {:?} should be {:?}", value, expected);
657+
let expected = ScalarMaybeUndef::from(Scalar::from_bool(*expected));
658+
let value_const = self.ecx.read_scalar(value).unwrap();
659+
if expected != value_const {
660+
// poison all places this operand references so that further code
661+
// doesn't use the invalid value
662+
match cond {
663+
Operand::Move(ref place) | Operand::Copy(ref place) => {
664+
let mut place = place;
665+
while let Place::Projection(ref proj) = *place {
666+
place = &proj.base;
667+
}
668+
if let Place::Base(PlaceBase::Local(local)) = *place {
669+
self.places[local] = None;
670+
}
671+
},
672+
Operand::Constant(_) => {}
673+
}
674+
let span = terminator.source_info.span;
675+
let hir_id = self
676+
.tcx
677+
.hir()
678+
.as_local_hir_id(self.source.def_id())
679+
.expect("some part of a failing const eval must be local");
680+
use rustc::mir::interpret::InterpError::*;
681+
let msg = match msg {
682+
Overflow(_) |
683+
OverflowNeg |
684+
DivisionByZero |
685+
RemainderByZero => msg.description().to_owned(),
686+
BoundsCheck { ref len, ref index } => {
687+
let len = self
688+
.eval_operand(len, source_info)
689+
.expect("len must be const");
690+
let len = match self.ecx.read_scalar(len) {
691+
Ok(ScalarMaybeUndef::Scalar(Scalar::Bits {
692+
bits, ..
693+
})) => bits,
694+
other => bug!("const len not primitive: {:?}", other),
695+
};
696+
let index = self
697+
.eval_operand(index, source_info)
698+
.expect("index must be const");
699+
let index = match self.ecx.read_scalar(index) {
700+
Ok(ScalarMaybeUndef::Scalar(Scalar::Bits {
701+
bits, ..
702+
})) => bits,
703+
other => bug!("const index not primitive: {:?}", other),
704+
};
705+
format!(
706+
"index out of bounds: \
707+
the len is {} but the index is {}",
708+
len,
709+
index,
710+
)
711+
},
712+
// Need proper const propagator for these
713+
_ => return,
714+
};
715+
self.tcx.lint_hir(
716+
::rustc::lint::builtin::CONST_ERR,
717+
hir_id,
718+
span,
719+
&msg,
720+
);
721+
} else {
722+
if let ScalarMaybeUndef::Scalar(scalar) = value_const {
723+
*cond = self.operand_from_scalar(scalar, self.tcx.types.bool);
724+
}
671725
}
672-
let span = terminator.source_info.span;
673-
let hir_id = self
674-
.tcx
675-
.hir()
676-
.as_local_hir_id(self.source.def_id())
677-
.expect("some part of a failing const eval must be local");
678-
use rustc::mir::interpret::InterpError::*;
679-
let msg = match msg {
680-
Overflow(_) |
681-
OverflowNeg |
682-
DivisionByZero |
683-
RemainderByZero => msg.description().to_owned(),
684-
BoundsCheck { ref len, ref index } => {
685-
let len = self
686-
.eval_operand(len, source_info)
687-
.expect("len must be const");
688-
let len = match self.ecx.read_scalar(len) {
689-
Ok(ScalarMaybeUndef::Scalar(Scalar::Bits {
690-
bits, ..
691-
})) => bits,
692-
other => bug!("const len not primitive: {:?}", other),
693-
};
694-
let index = self
695-
.eval_operand(index, source_info)
696-
.expect("index must be const");
697-
let index = match self.ecx.read_scalar(index) {
698-
Ok(ScalarMaybeUndef::Scalar(Scalar::Bits {
699-
bits, ..
700-
})) => bits,
701-
other => bug!("const index not primitive: {:?}", other),
702-
};
703-
format!(
704-
"index out of bounds: \
705-
the len is {} but the index is {}",
706-
len,
707-
index,
708-
)
709-
},
710-
// Need proper const propagator for these
711-
_ => return,
712-
};
713-
self.tcx.lint_hir(
714-
::rustc::lint::builtin::CONST_ERR,
715-
hir_id,
716-
span,
717-
&msg,
718-
);
719726
}
720-
}
727+
},
728+
_ => {}
721729
}
722730
}
723731
}

src/test/mir-opt/const_prop/array_index.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ fn main() {
2323
// bb0: {
2424
// ...
2525
// _5 = const true;
26-
// assert(move _5, "index out of bounds: the len is move _4 but the index is _3") -> bb1;
26+
// assert(const true, "index out of bounds: the len is move _4 but the index is _3") -> bb1;
2727
// }
2828
// bb1: {
2929
// _1 = _2[_3];

src/test/mir-opt/const_prop/checked_add.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,6 @@ fn main() {
1616
// bb0: {
1717
// ...
1818
// _2 = (const 2u32, const false);
19-
// assert(!move (_2.1: bool), "attempt to add with overflow") -> bb1;
19+
// assert(!const false, "attempt to add with overflow") -> bb1;
2020
// }
2121
// END rustc.main.ConstProp.after.mir

0 commit comments

Comments
 (0)