@@ -76,8 +76,7 @@ pub struct Frame<'mir, 'tcx: 'mir, Tag=(), Extra=()> {
7676 /// The locals are stored as `Option<Value>`s.
7777 /// `None` represents a local that is currently dead, while a live local
7878 /// can either directly contain `Scalar` or refer to some part of an `Allocation`.
79- pub locals : IndexVec < mir:: Local , LocalValue < Tag > > ,
80- pub local_layouts : IndexVec < mir:: Local , Cell < Option < TyLayout < ' tcx > > > > ,
79+ pub locals : IndexVec < mir:: Local , LocalValue < ' tcx , Tag > > ,
8180
8281 ////////////////////////////////////////////////////////////////////////////////
8382 // Current position within the function
@@ -106,9 +105,17 @@ pub enum StackPopCleanup {
106105 None { cleanup : bool } ,
107106}
108107
109- // State of a local variable
108+ /// State of a local variable including a memoized layout
109+ #[ derive( Clone , PartialEq , Eq ) ]
110+ pub struct LocalValue < ' tcx , Tag =( ) , Id =AllocId > {
111+ pub state : LocalState < Tag , Id > ,
112+ /// Don't modify if `Some`, this is only used to prevent computing the layout twice
113+ pub layout : Cell < Option < TyLayout < ' tcx > > > ,
114+ }
115+
116+ /// State of a local variable
110117#[ derive( Copy , Clone , PartialEq , Eq , Hash ) ]
111- pub enum LocalValue < Tag =( ) , Id =AllocId > {
118+ pub enum LocalState < Tag =( ) , Id =AllocId > {
112119 Dead ,
113120 // Mostly for convenience, we re-use the `Operand` type here.
114121 // This is an optimization over just always having a pointer here;
@@ -117,18 +124,18 @@ pub enum LocalValue<Tag=(), Id=AllocId> {
117124 Live ( Operand < Tag , Id > ) ,
118125}
119126
120- impl < ' tcx , Tag > LocalValue < Tag > {
127+ impl < ' tcx , Tag > LocalValue < ' tcx , Tag > {
121128 pub fn access ( & self ) -> EvalResult < ' tcx , & Operand < Tag > > {
122- match self {
123- LocalValue :: Dead => err ! ( DeadLocal ) ,
124- LocalValue :: Live ( ref val) => Ok ( val) ,
129+ match self . state {
130+ LocalState :: Dead => err ! ( DeadLocal ) ,
131+ LocalState :: Live ( ref val) => Ok ( val) ,
125132 }
126133 }
127134
128135 pub fn access_mut ( & mut self ) -> EvalResult < ' tcx , & mut Operand < Tag > > {
129- match self {
130- LocalValue :: Dead => err ! ( DeadLocal ) ,
131- LocalValue :: Live ( ref mut val) => Ok ( val) ,
136+ match self . state {
137+ LocalState :: Dead => err ! ( DeadLocal ) ,
138+ LocalState :: Live ( ref mut val) => Ok ( val) ,
132139 }
133140 }
134141}
@@ -312,7 +319,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
312319 frame : & Frame < ' mir , ' tcx , M :: PointerTag , M :: FrameExtra > ,
313320 local : mir:: Local
314321 ) -> EvalResult < ' tcx , TyLayout < ' tcx > > {
315- let cell = & frame. local_layouts [ local] ;
322+ let cell = & frame. locals [ local] . layout ;
316323 if cell. get ( ) . is_none ( ) {
317324 let local_ty = frame. mir . local_decls [ local] . ty ;
318325 let local_ty = self . monomorphize_with_substs ( local_ty, frame. instance . substs ) ;
@@ -454,7 +461,6 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
454461 // empty local array, we fill it in below, after we are inside the stack frame and
455462 // all methods actually know about the frame
456463 locals : IndexVec :: new ( ) ,
457- local_layouts : IndexVec :: from_elem_n ( Default :: default ( ) , mir. local_decls . len ( ) ) ,
458464 span,
459465 instance,
460466 stmt : 0 ,
@@ -464,14 +470,18 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
464470 // don't allocate at all for trivial constants
465471 if mir. local_decls . len ( ) > 1 {
466472 // We put some marker immediate into the locals that we later want to initialize.
467- // This can be anything except for LocalValue ::Dead -- because *that* is the
473+ // This can be anything except for LocalState ::Dead -- because *that* is the
468474 // value we use for things that we know are initially dead.
469- let dummy =
470- LocalValue :: Live ( Operand :: Immediate ( Immediate :: Scalar ( ScalarMaybeUndef :: Undef ) ) ) ;
475+ let dummy = LocalValue {
476+ state : LocalState :: Live ( Operand :: Immediate ( Immediate :: Scalar (
477+ ScalarMaybeUndef :: Undef ,
478+ ) ) ) ,
479+ layout : Cell :: new ( None ) ,
480+ } ;
471481 let mut locals = IndexVec :: from_elem ( dummy, & mir. local_decls ) ;
472482 // Return place is handled specially by the `eval_place` functions, and the
473483 // entry in `locals` should never be used. Make it dead, to be sure.
474- locals[ mir:: RETURN_PLACE ] = LocalValue :: Dead ;
484+ locals[ mir:: RETURN_PLACE ] . state = LocalState :: Dead ;
475485 // Now mark those locals as dead that we do not want to initialize
476486 match self . tcx . describe_def ( instance. def_id ( ) ) {
477487 // statics and constants don't have `Storage*` statements, no need to look for them
@@ -484,7 +494,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
484494 match stmt. kind {
485495 StorageLive ( local) |
486496 StorageDead ( local) => {
487- locals[ local] = LocalValue :: Dead ;
497+ locals[ local] . state = LocalState :: Dead ;
488498 }
489499 _ => { }
490500 }
@@ -494,13 +504,13 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
494504 }
495505 // Finally, properly initialize all those that still have the dummy value
496506 for ( idx, local) in locals. iter_enumerated_mut ( ) {
497- match * local {
498- LocalValue :: Live ( _) => {
507+ match local. state {
508+ LocalState :: Live ( _) => {
499509 // This needs to be peoperly initialized.
500510 let layout = self . layout_of_local ( self . frame ( ) , idx) ?;
501- * local = LocalValue :: Live ( self . uninit_operand ( layout) ?) ;
511+ local. state = LocalState :: Live ( self . uninit_operand ( layout) ?) ;
502512 }
503- LocalValue :: Dead => {
513+ LocalState :: Dead => {
504514 // Nothing to do
505515 }
506516 }
@@ -543,7 +553,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
543553 }
544554 // Deallocate all locals that are backed by an allocation.
545555 for local in frame. locals {
546- self . deallocate_local ( local) ?;
556+ self . deallocate_local ( local. state ) ?;
547557 }
548558 // Validate the return value. Do this after deallocating so that we catch dangling
549559 // references.
@@ -587,31 +597,31 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tc
587597 pub fn storage_live (
588598 & mut self ,
589599 local : mir:: Local
590- ) -> EvalResult < ' tcx , LocalValue < M :: PointerTag > > {
600+ ) -> EvalResult < ' tcx , LocalState < M :: PointerTag > > {
591601 assert ! ( local != mir:: RETURN_PLACE , "Cannot make return place live" ) ;
592602 trace ! ( "{:?} is now live" , local) ;
593603
594604 let layout = self . layout_of_local ( self . frame ( ) , local) ?;
595- let init = LocalValue :: Live ( self . uninit_operand ( layout) ?) ;
605+ let init = LocalState :: Live ( self . uninit_operand ( layout) ?) ;
596606 // StorageLive *always* kills the value that's currently stored
597- Ok ( mem:: replace ( & mut self . frame_mut ( ) . locals [ local] , init) )
607+ Ok ( mem:: replace ( & mut self . frame_mut ( ) . locals [ local] . state , init) )
598608 }
599609
600610 /// Returns the old value of the local.
601611 /// Remember to deallocate that!
602- pub fn storage_dead ( & mut self , local : mir:: Local ) -> LocalValue < M :: PointerTag > {
612+ pub fn storage_dead ( & mut self , local : mir:: Local ) -> LocalState < M :: PointerTag > {
603613 assert ! ( local != mir:: RETURN_PLACE , "Cannot make return place dead" ) ;
604614 trace ! ( "{:?} is now dead" , local) ;
605615
606- mem:: replace ( & mut self . frame_mut ( ) . locals [ local] , LocalValue :: Dead )
616+ mem:: replace ( & mut self . frame_mut ( ) . locals [ local] . state , LocalState :: Dead )
607617 }
608618
609619 pub ( super ) fn deallocate_local (
610620 & mut self ,
611- local : LocalValue < M :: PointerTag > ,
621+ local : LocalState < M :: PointerTag > ,
612622 ) -> EvalResult < ' tcx > {
613623 // FIXME: should we tell the user that there was a local which was never written to?
614- if let LocalValue :: Live ( Operand :: Indirect ( MemPlace { ptr, .. } ) ) = local {
624+ if let LocalState :: Live ( Operand :: Indirect ( MemPlace { ptr, .. } ) ) = local {
615625 trace ! ( "deallocating local" ) ;
616626 let ptr = ptr. to_ptr ( ) ?;
617627 self . memory . dump_alloc ( ptr. alloc_id ) ;
0 commit comments