@@ -108,34 +108,51 @@ pub enum StackPopCleanup {
108108/// State of a local variable including a memoized layout
109109#[ derive( Clone , PartialEq , Eq ) ]
110110pub struct LocalState < ' tcx , Tag =( ) , Id =AllocId > {
111- pub state : LocalValue < Tag , Id > ,
111+ pub value : LocalValue < Tag , Id > ,
112112 /// Don't modify if `Some`, this is only used to prevent computing the layout twice
113113 pub layout : Cell < Option < TyLayout < ' tcx > > > ,
114114}
115115
116- /// State of a local variable
117- #[ derive( Copy , Clone , PartialEq , Eq , Hash ) ]
116+ /// Current value of a local variable
117+ #[ derive( Copy , Clone , PartialEq , Eq , Hash , Debug ) ]
118118pub enum LocalValue < Tag =( ) , Id =AllocId > {
119+ /// This local is not currently alive, and cannot be used at all.
119120 Dead ,
120- // Mostly for convenience, we re-use the `Operand` type here.
121- // This is an optimization over just always having a pointer here;
122- // we can thus avoid doing an allocation when the local just stores
123- // immediate values *and* never has its address taken.
121+ /// This local is alive but not yet initialized. It can be written to
122+ /// but not read from or its address taken. Locals get initialized on
123+ /// first write because for unsized locals, we do not know their size
124+ /// before that.
125+ Uninitialized ,
126+ /// A normal, live local.
127+ /// Mostly for convenience, we re-use the `Operand` type here.
128+ /// This is an optimization over just always having a pointer here;
129+ /// we can thus avoid doing an allocation when the local just stores
130+ /// immediate values *and* never has its address taken.
124131 Live ( Operand < Tag , Id > ) ,
125132}
126133
127- impl < ' tcx , Tag > LocalState < ' tcx , Tag > {
128- pub fn access ( & self ) -> EvalResult < ' tcx , & Operand < Tag > > {
129- match self . state {
134+ impl < ' tcx , Tag : Copy + ' static > LocalState < ' tcx , Tag > {
135+ pub fn access ( & self ) -> EvalResult < ' tcx , Operand < Tag > > {
136+ match self . value {
130137 LocalValue :: Dead => err ! ( DeadLocal ) ,
131- LocalValue :: Live ( ref val) => Ok ( val) ,
138+ LocalValue :: Uninitialized =>
139+ bug ! ( "The type checker should prevent reading from a never-written local" ) ,
140+ LocalValue :: Live ( val) => Ok ( val) ,
132141 }
133142 }
134143
135- pub fn access_mut ( & mut self ) -> EvalResult < ' tcx , & mut Operand < Tag > > {
136- match self . state {
144+ /// Overwrite the local. If the local can be overwritten in place, return a reference
145+ /// to do so; otherwise return the `MemPlace` to consult instead.
146+ pub fn access_mut (
147+ & mut self ,
148+ ) -> EvalResult < ' tcx , Result < & mut LocalValue < Tag > , MemPlace < Tag > > > {
149+ match self . value {
137150 LocalValue :: Dead => err ! ( DeadLocal ) ,
138- LocalValue :: Live ( ref mut val) => Ok ( val) ,
151+ LocalValue :: Live ( Operand :: Indirect ( mplace) ) => Ok ( Err ( mplace) ) ,
152+ ref mut local @ LocalValue :: Live ( Operand :: Immediate ( _) ) |
153+ ref mut local @ LocalValue :: Uninitialized => {
154+ Ok ( Ok ( local) )
155+ }
139156 }
140157 }
141158}
@@ -327,6 +344,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tc
327344 let local_ty = self . monomorphize_with_substs ( local_ty, frame. instance . substs ) ;
328345 self . layout_of ( local_ty)
329346 } ) ?;
347+ // Layouts of locals are requested a lot, so we cache them.
330348 frame. locals [ local] . layout . set ( Some ( layout) ) ;
331349 Ok ( layout)
332350 }
@@ -473,19 +491,15 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tc
473491
474492 // don't allocate at all for trivial constants
475493 if mir. local_decls . len ( ) > 1 {
476- // We put some marker immediate into the locals that we later want to initialize.
477- // This can be anything except for LocalValue::Dead -- because *that* is the
478- // value we use for things that we know are initially dead.
494+ // Locals are initially uninitialized.
479495 let dummy = LocalState {
480- state : LocalValue :: Live ( Operand :: Immediate ( Immediate :: Scalar (
481- ScalarMaybeUndef :: Undef ,
482- ) ) ) ,
496+ value : LocalValue :: Uninitialized ,
483497 layout : Cell :: new ( None ) ,
484498 } ;
485499 let mut locals = IndexVec :: from_elem ( dummy, & mir. local_decls ) ;
486500 // Return place is handled specially by the `eval_place` functions, and the
487501 // entry in `locals` should never be used. Make it dead, to be sure.
488- locals[ mir:: RETURN_PLACE ] . state = LocalValue :: Dead ;
502+ locals[ mir:: RETURN_PLACE ] . value = LocalValue :: Dead ;
489503 // Now mark those locals as dead that we do not want to initialize
490504 match self . tcx . describe_def ( instance. def_id ( ) ) {
491505 // statics and constants don't have `Storage*` statements, no need to look for them
@@ -498,29 +512,14 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tc
498512 match stmt. kind {
499513 StorageLive ( local) |
500514 StorageDead ( local) => {
501- locals[ local] . state = LocalValue :: Dead ;
515+ locals[ local] . value = LocalValue :: Dead ;
502516 }
503517 _ => { }
504518 }
505519 }
506520 }
507521 } ,
508522 }
509- // Finally, properly initialize all those that still have the dummy value
510- for ( idx, local) in locals. iter_enumerated_mut ( ) {
511- match local. state {
512- LocalValue :: Live ( _) => {
513- // This needs to be properly initialized.
514- let ty = self . monomorphize ( mir. local_decls [ idx] . ty ) ?;
515- let layout = self . layout_of ( ty) ?;
516- local. state = LocalValue :: Live ( self . uninit_operand ( layout) ?) ;
517- local. layout = Cell :: new ( Some ( layout) ) ;
518- }
519- LocalValue :: Dead => {
520- // Nothing to do
521- }
522- }
523- }
524523 // done
525524 self . frame_mut ( ) . locals = locals;
526525 }
@@ -555,7 +554,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tc
555554 }
556555 // Deallocate all locals that are backed by an allocation.
557556 for local in frame. locals {
558- self . deallocate_local ( local. state ) ?;
557+ self . deallocate_local ( local. value ) ?;
559558 }
560559 // Validate the return value. Do this after deallocating so that we catch dangling
561560 // references.
@@ -603,10 +602,9 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tc
603602 assert ! ( local != mir:: RETURN_PLACE , "Cannot make return place live" ) ;
604603 trace ! ( "{:?} is now live" , local) ;
605604
606- let layout = self . layout_of_local ( self . frame ( ) , local, None ) ?;
607- let init = LocalValue :: Live ( self . uninit_operand ( layout) ?) ;
605+ let local_val = LocalValue :: Uninitialized ;
608606 // StorageLive *always* kills the value that's currently stored
609- Ok ( mem:: replace ( & mut self . frame_mut ( ) . locals [ local] . state , init ) )
607+ Ok ( mem:: replace ( & mut self . frame_mut ( ) . locals [ local] . value , local_val ) )
610608 }
611609
612610 /// Returns the old value of the local.
@@ -615,7 +613,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tc
615613 assert ! ( local != mir:: RETURN_PLACE , "Cannot make return place dead" ) ;
616614 trace ! ( "{:?} is now dead" , local) ;
617615
618- mem:: replace ( & mut self . frame_mut ( ) . locals [ local] . state , LocalValue :: Dead )
616+ mem:: replace ( & mut self . frame_mut ( ) . locals [ local] . value , LocalValue :: Dead )
619617 }
620618
621619 pub ( super ) fn deallocate_local (
@@ -668,31 +666,31 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tc
668666 }
669667 write ! ( msg, ":" ) . unwrap ( ) ;
670668
671- match self . stack [ frame] . locals [ local] . access ( ) {
672- Err ( err) => {
673- if let InterpError :: DeadLocal = err. kind {
674- write ! ( msg, " is dead" ) . unwrap ( ) ;
675- } else {
676- panic ! ( "Failed to access local: {:?}" , err) ;
677- }
678- }
679- Ok ( Operand :: Indirect ( mplace) ) => {
680- let ( ptr, align) = mplace. to_scalar_ptr_align ( ) ;
681- match ptr {
669+ match self . stack [ frame] . locals [ local] . value {
670+ LocalValue :: Dead => write ! ( msg, " is dead" ) . unwrap ( ) ,
671+ LocalValue :: Uninitialized => write ! ( msg, " is uninitialized" ) . unwrap ( ) ,
672+ LocalValue :: Live ( Operand :: Indirect ( mplace) ) => {
673+ match mplace. ptr {
682674 Scalar :: Ptr ( ptr) => {
683- write ! ( msg, " by align({}) ref:" , align. bytes( ) ) . unwrap ( ) ;
675+ write ! ( msg, " by align({}){} ref:" ,
676+ mplace. align. bytes( ) ,
677+ match mplace. meta {
678+ Some ( meta) => format!( " meta({:?})" , meta) ,
679+ None => String :: new( )
680+ }
681+ ) . unwrap ( ) ;
684682 allocs. push ( ptr. alloc_id ) ;
685683 }
686684 ptr => write ! ( msg, " by integral ref: {:?}" , ptr) . unwrap ( ) ,
687685 }
688686 }
689- Ok ( Operand :: Immediate ( Immediate :: Scalar ( val) ) ) => {
687+ LocalValue :: Live ( Operand :: Immediate ( Immediate :: Scalar ( val) ) ) => {
690688 write ! ( msg, " {:?}" , val) . unwrap ( ) ;
691689 if let ScalarMaybeUndef :: Scalar ( Scalar :: Ptr ( ptr) ) = val {
692690 allocs. push ( ptr. alloc_id ) ;
693691 }
694692 }
695- Ok ( Operand :: Immediate ( Immediate :: ScalarPair ( val1, val2) ) ) => {
693+ LocalValue :: Live ( Operand :: Immediate ( Immediate :: ScalarPair ( val1, val2) ) ) => {
696694 write ! ( msg, " ({:?}, {:?})" , val1, val2) . unwrap ( ) ;
697695 if let ScalarMaybeUndef :: Scalar ( Scalar :: Ptr ( ptr) ) = val1 {
698696 allocs. push ( ptr. alloc_id ) ;
0 commit comments