@@ -628,35 +628,30 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
628628 let frame = M :: init_frame_extra ( self , pre_frame) ?;
629629 self . stack_mut ( ) . push ( frame) ;
630630
631- // don't allocate at all for trivial constants
632- if body. local_decls . len ( ) > 1 {
633- // Locals are initially uninitialized.
634- let dummy = LocalState { value : LocalValue :: Uninitialized , layout : Cell :: new ( None ) } ;
635- let mut locals = IndexVec :: from_elem ( dummy, & body. local_decls ) ;
636- // Return place is handled specially by the `eval_place` functions, and the
637- // entry in `locals` should never be used. Make it dead, to be sure.
638- locals[ mir:: RETURN_PLACE ] . value = LocalValue :: Dead ;
639- // Now mark those locals as dead that we do not want to initialize
640- match self . tcx . def_kind ( instance. def_id ( ) ) {
641- // statics and constants don't have `Storage*` statements, no need to look for them
642- //
643- // FIXME: The above is likely untrue. See
644- // <https://github.com/rust-lang/rust/pull/70004#issuecomment-602022110>. Is it
645- // okay to ignore `StorageDead`/`StorageLive` annotations during CTFE?
646- Some ( DefKind :: Static | DefKind :: Const | DefKind :: AssocConst ) => { }
647- _ => {
648- // Mark locals that use `Storage*` annotations as dead on function entry.
649- let always_live = AlwaysLiveLocals :: new ( self . body ( ) ) ;
650- for local in locals. indices ( ) {
651- if !always_live. contains ( local) {
652- locals[ local] . value = LocalValue :: Dead ;
653- }
631+ // Locals are initially uninitialized.
632+ let dummy = LocalState { value : LocalValue :: Uninitialized , layout : Cell :: new ( None ) } ;
633+ let mut locals = IndexVec :: from_elem ( dummy, & body. local_decls ) ;
634+
635+ // Now mark those locals as dead that we do not want to initialize
636+ match self . tcx . def_kind ( instance. def_id ( ) ) {
637+ // statics and constants don't have `Storage*` statements, no need to look for them
638+ //
639+ // FIXME: The above is likely untrue. See
640+ // <https://github.com/rust-lang/rust/pull/70004#issuecomment-602022110>. Is it
641+ // okay to ignore `StorageDead`/`StorageLive` annotations during CTFE?
642+ Some ( DefKind :: Static | DefKind :: Const | DefKind :: AssocConst ) => { }
643+ _ => {
644+ // Mark locals that use `Storage*` annotations as dead on function entry.
645+ let always_live = AlwaysLiveLocals :: new ( self . body ( ) ) ;
646+ for local in locals. indices ( ) {
647+ if !always_live. contains ( local) {
648+ locals[ local] . value = LocalValue :: Dead ;
654649 }
655650 }
656651 }
657- // done
658- self . frame_mut ( ) . locals = locals;
659652 }
653+ // done
654+ self . frame_mut ( ) . locals = locals;
660655
661656 M :: after_stack_push ( self ) ?;
662657 info ! ( "ENTERING({}) {}" , self . frame_idx( ) , self . frame( ) . instance) ;
@@ -734,6 +729,17 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
734729 let frame =
735730 self . stack_mut ( ) . pop ( ) . expect ( "tried to pop a stack frame, but there were none" ) ;
736731
732+ if !unwinding {
733+ // Copy the return value to the caller's stack frame.
734+ if let Some ( return_place) = frame. return_place {
735+ let op = self . access_local ( & frame, mir:: RETURN_PLACE , None ) ?;
736+ self . copy_op_transmute ( op, return_place) ?;
737+ self . dump_place ( * return_place) ;
738+ } else {
739+ throw_ub ! ( Unreachable ) ;
740+ }
741+ }
742+
737743 // Now where do we jump next?
738744
739745 // Usually we want to clean up (deallocate locals), but in a few rare cases we don't.
@@ -759,7 +765,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
759765 self . deallocate_local ( local. value ) ?;
760766 }
761767
762- let return_place = frame. return_place ;
763768 if M :: after_stack_pop ( self , frame, unwinding) ? == StackPopJump :: NoJump {
764769 // The hook already did everything.
765770 // We want to skip the `info!` below, hence early return.
@@ -772,25 +777,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
772777 self . unwind_to_block ( unwind) ;
773778 } else {
774779 // Follow the normal return edge.
775- // Validate the return value. Do this after deallocating so that we catch dangling
776- // references.
777- if let Some ( return_place) = return_place {
778- if M :: enforce_validity ( self ) {
779- // Data got changed, better make sure it matches the type!
780- // It is still possible that the return place held invalid data while
781- // the function is running, but that's okay because nobody could have
782- // accessed that same data from the "outside" to observe any broken
783- // invariant -- that is, unless a function somehow has a ptr to
784- // its return place... but the way MIR is currently generated, the
785- // return place is always a local and then this cannot happen.
786- self . validate_operand ( self . place_to_op ( return_place) ?) ?;
787- }
788- } else {
789- // Uh, that shouldn't happen... the function did not intend to return
790- throw_ub ! ( Unreachable ) ;
791- }
792-
793- // Jump to new block -- *after* validation so that the spans make more sense.
794780 if let Some ( ret) = next_block {
795781 self . return_to_block ( ret) ?;
796782 }
0 commit comments