@@ -116,26 +116,41 @@ pub struct LocalState<'tcx, Tag=(), Id=AllocId> {
116
116
/// State of a local variable
117
117
#[ derive( Copy , Clone , PartialEq , Eq , Hash ) ]
118
118
pub enum LocalValue < Tag =( ) , Id =AllocId > {
119
+ /// This local is not currently alive, and cannot be used at all.
119
120
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.
124
131
Live ( Operand < Tag , Id > ) ,
125
132
}
126
133
127
- impl < ' tcx , Tag > LocalState < ' tcx , Tag > {
134
+ impl < ' tcx , Tag : Copy > LocalState < ' tcx , Tag > {
128
135
pub fn access ( & self ) -> EvalResult < ' tcx , & Operand < Tag > > {
129
136
match self . state {
130
- LocalValue :: Dead => err ! ( DeadLocal ) ,
137
+ LocalValue :: Dead | LocalValue :: Uninitialized => err ! ( DeadLocal ) ,
131
138
LocalValue :: Live ( ref val) => Ok ( val) ,
132
139
}
133
140
}
134
141
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 > > > {
136
147
match self . state {
137
148
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
+ }
139
154
}
140
155
}
141
156
}
@@ -327,6 +342,7 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tc
327
342
let local_ty = self . monomorphize_with_substs ( local_ty, frame. instance . substs ) ;
328
343
self . layout_of ( local_ty)
329
344
} ) ?;
345
+ // Layouts of locals are requested a lot, so we cache them.
330
346
frame. locals [ local] . layout . set ( Some ( layout) ) ;
331
347
Ok ( layout)
332
348
}
@@ -473,13 +489,9 @@ impl<'a, 'mir, 'tcx: 'mir, M: Machine<'a, 'mir, 'tcx>> InterpretCx<'a, 'mir, 'tc
473
489
474
490
// don't allocate at all for trivial constants
475
491
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.
479
493
let dummy = LocalState {
480
- state : LocalValue :: Live ( Operand :: Immediate ( Immediate :: Scalar (
481
- ScalarMaybeUndef :: Undef ,
482
- ) ) ) ,
494
+ state : LocalValue :: Uninitialized ,
483
495
layout : Cell :: new ( None ) ,
484
496
} ;
485
497
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
506
518
}
507
519
} ,
508
520
}
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.
510
525
for ( idx, local) in locals. iter_enumerated_mut ( ) {
511
526
match local. state {
512
- LocalValue :: Live ( _ ) => {
527
+ LocalValue :: Uninitialized => {
513
528
// This needs to be properly initialized.
514
529
let ty = self . monomorphize ( mir. local_decls [ idx] . ty ) ?;
515
530
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
+ }
517
534
local. layout = Cell :: new ( Some ( layout) ) ;
518
535
}
519
536
LocalValue :: Dead => {
520
537
// Nothing to do
521
538
}
539
+ LocalValue :: Live ( _) => bug ! ( "Locals cannot be live yet" ) ,
522
540
}
523
541
}
524
542
// done
0 commit comments