@@ -492,7 +492,24 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
492
492
let frame = self . stack . pop ( ) . expect (
493
493
"tried to pop a stack frame, but there were none" ,
494
494
) ;
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.
496
513
if let Some ( return_place) = frame. return_place {
497
514
if M :: enforce_validity ( self ) {
498
515
// 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
518
535
StackPopCleanup :: Goto ( block) => {
519
536
self . goto_block ( block) ?;
520
537
}
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 { .. } => { }
531
539
}
532
540
533
541
if self . stack . len ( ) > 1 { // FIXME should be "> 0", printing topmost frame crashes rustc...
0 commit comments