diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 1471e15baa5..b5dbaaa2327 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -59,7 +59,7 @@ impl MirPass for ConstProp { trace!("ConstProp starting for {:?}", source.def_id()); - // steal some data we need from `body` + // Steal some data we need from `body`. let source_scope_local_data = std::mem::replace( &mut body.source_scope_local_data, ClearCrossCrate::Clear @@ -188,31 +188,49 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { } } - fn release_stolen_data(self) -> - (ClearCrossCrate>, - IndexVec>) - { + fn release_stolen_data( + self, + ) -> ( + ClearCrossCrate>, + IndexVec>, + ) { (self.source_scope_local_data, self.promoted) } fn get_const(&self, local: Local) -> Option> { let l = &self.ecx.frame().locals[local]; - if l.value == LocalValue::Uninitialized || l.value == LocalValue::Dead { + + // If the local is `Unitialized` or `Dead` then we haven't propagated a value into it. + // + // `InterpretCx::access_local()` mostly takes care of this for us however, for ZSTs, + // it will synthesize a value for us. In doing so, that will cause the + // `get_const(l).is_empty()` assert right before we call `set_const()` in `visit_statement` + // to fail. + if let LocalValue::Uninitialized | LocalValue::Dead = l.value { return None; } self.ecx.access_local(self.ecx.frame(), local, None).ok() } - fn set_const(&mut self, local: Local, c: Option>) { - self.ecx.frame_mut().locals[local] = - match c { - Some(op_ty) => LocalState { - value: LocalValue::Live(*op_ty), - layout: Cell::new(Some(op_ty.layout)), - }, - None => LocalState { value: LocalValue::Uninitialized, layout: Cell::new(None) }, - }; + fn set_const(&mut self, local: Local, c: Const<'tcx>) { + let frame = self.ecx.frame_mut(); + + if let Some(layout) = frame.locals[local].layout.get() { + debug_assert_eq!(c.layout, layout); + } + + frame.locals[local] = LocalState { + value: LocalValue::Live(*c), + layout: Cell::new(Some(c.layout)), + }; + } + + fn remove_const(&mut self, local: Local) { + self.ecx.frame_mut().locals[local] = LocalState { + value: LocalValue::Uninitialized, + layout: Cell::new(None), + }; } fn use_ecx( @@ -768,7 +786,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { if self.can_const_prop[local] { trace!("storing {:?} to {:?}", value, local); assert!(self.get_const(local).is_none()); - self.set_const(local, Some(value)); + self.set_const(local, value); if self.should_const_prop() { self.replace_with_const( @@ -808,7 +826,7 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { place = &proj.base; } if let Place::Base(PlaceBase::Local(local)) = *place { - self.set_const(local, None); + self.remove_const(local); } }, Operand::Constant(_) => {}