@@ -116,26 +116,41 @@ pub struct LocalState<'tcx, Tag=(), Id=AllocId> {
116116/// State of a local variable
117117#[ derive( Copy , Clone , PartialEq , Eq , Hash ) ]
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 > {
134+ impl < ' tcx , Tag : Copy > LocalState < ' tcx , Tag > {
128135 pub fn access ( & self ) -> EvalResult < ' tcx , & Operand < Tag > > {
129136 match self . state {
130- LocalValue :: Dead => err ! ( DeadLocal ) ,
137+ LocalValue :: Dead | LocalValue :: Uninitialized => err ! ( DeadLocal ) ,
131138 LocalValue :: Live ( ref val) => Ok ( val) ,
132139 }
133140 }
134141
135- pub fn access_mut ( & mut self ) -> EvalResult < ' tcx , & mut Operand < Tag > > {
142+ /// Overwrite the local. If the local can be overwritten in place, return a reference
143+ /// to do so; otherwise return the `MemPlace` to consult instead.
144+ pub fn access_mut (
145+ & mut self ,
146+ ) -> EvalResult < ' tcx , Result < & mut LocalValue < Tag > , MemPlace < Tag > > > {
136147 match self . state {
137148 LocalValue :: Dead => err ! ( DeadLocal ) ,
138- LocalValue :: Live ( ref mut val) => Ok ( val) ,
149+ LocalValue :: Live ( Operand :: Indirect ( mplace) ) => Ok ( Err ( mplace) ) ,
150+ ref mut local @ LocalValue :: Live ( Operand :: Immediate ( _) ) |
151+ ref mut local @ LocalValue :: Uninitialized => {
152+ Ok ( Ok ( local) )
153+ }
139154 }
140155 }
141156}
@@ -327,6 +342,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tc
327342 let local_ty = self . monomorphize_with_substs ( local_ty, frame. instance . substs ) ;
328343 self . layout_of ( local_ty)
329344 } ) ?;
345+ // Layouts of locals are requested a lot, so we cache them.
330346 frame. locals [ local] . layout . set ( Some ( layout) ) ;
331347 Ok ( layout)
332348 }
@@ -473,13 +489,9 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tc
473489
474490 // don't allocate at all for trivial constants
475491 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.
492+ // Locals are initially uninitialized.
479493 let dummy = LocalState {
480- state : LocalValue :: Live ( Operand :: Immediate ( Immediate :: Scalar (
481- ScalarMaybeUndef :: Undef ,
482- ) ) ) ,
494+ state : LocalValue :: Uninitialized ,
483495 layout : Cell :: new ( None ) ,
484496 } ;
485497 let mut locals = IndexVec :: from_elem ( dummy, & mir. local_decls ) ;
@@ -506,19 +518,25 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tc
506518 }
507519 } ,
508520 }
509- // Finally, properly initialize all those that still have the dummy value
521+ // FIXME: We initialize live ZST here. This should not be needed if MIR was
522+ // consistently generated for ZST, but that seems to not be the case -- there
523+ // is MIR (around promoteds in particular) that reads local ZSTs that never
524+ // were written to.
510525 for ( idx, local) in locals. iter_enumerated_mut ( ) {
511526 match local. state {
512- LocalValue :: Live ( _ ) => {
527+ LocalValue :: Uninitialized => {
513528 // This needs to be properly initialized.
514529 let ty = self . monomorphize ( mir. local_decls [ idx] . ty ) ?;
515530 let layout = self . layout_of ( ty) ?;
516- local. state = LocalValue :: Live ( self . uninit_operand ( layout) ?) ;
531+ if layout. is_zst ( ) {
532+ local. state = LocalValue :: Live ( self . uninit_operand ( layout) ?) ;
533+ }
517534 local. layout = Cell :: new ( Some ( layout) ) ;
518535 }
519536 LocalValue :: Dead => {
520537 // Nothing to do
521538 }
539+ LocalValue :: Live ( _) => bug ! ( "Locals cannot be live yet" ) ,
522540 }
523541 }
524542 // done
0 commit comments