@@ -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 
113113pub  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. 
119120Dead , 
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. 
124131Live ( 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