@@ -840,36 +840,31 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
840840 Ok ( ( ) )
841841 }
842842
843- /// Mark a storage as live, killing the previous content and returning it.
844- /// Remember to deallocate that!
845- pub fn storage_live (
846- & mut self ,
847- local : mir:: Local ,
848- ) -> InterpResult < ' tcx , LocalValue < M :: PointerTag > > {
843+ /// Mark a storage as live, killing the previous content.
844+ pub fn storage_live ( & mut self , local : mir:: Local ) -> InterpResult < ' tcx > {
849845 assert ! ( local != mir:: RETURN_PLACE , "Cannot make return place live" ) ;
850846 trace ! ( "{:?} is now live" , local) ;
851847
852848 let local_val = LocalValue :: Uninitialized ;
853- // StorageLive *always* kills the value that's currently stored.
854- // However, we do not error if the variable already is live;
855- // see <https://github.com/rust-lang/rust/issues/42371>.
856- Ok ( mem:: replace ( & mut self . frame_mut ( ) . locals [ local] . value , local_val) )
849+ // StorageLive expects the local to be dead, and marks it live.
850+ let old = mem:: replace ( & mut self . frame_mut ( ) . locals [ local] . value , local_val) ;
851+ if !matches ! ( old, LocalValue :: Dead ) {
852+ throw_ub_format ! ( "StorageLive on a local that was already live" ) ;
853+ }
854+ Ok ( ( ) )
857855 }
858856
859- /// Returns the old value of the local.
860- /// Remember to deallocate that!
861- pub fn storage_dead ( & mut self , local : mir:: Local ) -> LocalValue < M :: PointerTag > {
857+ pub fn storage_dead ( & mut self , local : mir:: Local ) -> InterpResult < ' tcx > {
862858 assert ! ( local != mir:: RETURN_PLACE , "Cannot make return place dead" ) ;
863859 trace ! ( "{:?} is now dead" , local) ;
864860
865- mem:: replace ( & mut self . frame_mut ( ) . locals [ local] . value , LocalValue :: Dead )
861+ // It is entirely okay for this local to be already dead (at least that's how we currently generate MIR)
862+ let old = mem:: replace ( & mut self . frame_mut ( ) . locals [ local] . value , LocalValue :: Dead ) ;
863+ self . deallocate_local ( old) ?;
864+ Ok ( ( ) )
866865 }
867866
868- pub ( super ) fn deallocate_local (
869- & mut self ,
870- local : LocalValue < M :: PointerTag > ,
871- ) -> InterpResult < ' tcx > {
872- // FIXME: should we tell the user that there was a local which was never written to?
867+ fn deallocate_local ( & mut self , local : LocalValue < M :: PointerTag > ) -> InterpResult < ' tcx > {
873868 if let LocalValue :: Live ( Operand :: Indirect ( MemPlace { ptr, .. } ) ) = local {
874869 // All locals have a backing allocation, even if the allocation is empty
875870 // due to the local having ZST type.
0 commit comments