@@ -492,7 +492,24 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
492492 let frame = self . stack . pop ( ) . expect (
493493 "tried to pop a stack frame, but there were none" ,
494494 ) ;
495- // Validate the return value.
495+ // Abort early if we do not want to clean up: We also avoid validation in that case,
496+ // because this is CTFE and the final value will be thoroughly validated anyway.
497+ match frame. return_to_block {
498+ StackPopCleanup :: Goto ( _) => { } ,
499+ StackPopCleanup :: None { cleanup } => {
500+ if !cleanup {
501+ assert ! ( self . stack. is_empty( ) , "only the topmost frame should ever be leaked" ) ;
502+ // Leak the locals, skip validation.
503+ return Ok ( ( ) ) ;
504+ }
505+ }
506+ }
507+ // Deallocate all locals that are backed by an allocation.
508+ for local in frame. locals {
509+ self . deallocate_local ( local) ?;
510+ }
511+ // Validate the return value. Do this after deallocating so that we catch dangling
512+ // references.
496513 if let Some ( return_place) = frame. return_place {
497514 if M :: enforce_validity ( self ) {
498515 // Data got changed, better make sure it matches the type!
@@ -518,16 +535,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
518535 StackPopCleanup :: Goto ( block) => {
519536 self . goto_block ( block) ?;
520537 }
521- StackPopCleanup :: None { cleanup } => {
522- if !cleanup {
523- // Leak the locals.
524- return Ok ( ( ) ) ;
525- }
526- }
527- }
528- // Deallocate all locals that are backed by an allocation.
529- for local in frame. locals {
530- self . deallocate_local ( local) ?;
538+ StackPopCleanup :: None { .. } => { }
531539 }
532540
533541 if self . stack . len ( ) > 1 { // FIXME should be "> 0", printing topmost frame crashes rustc...
0 commit comments