@@ -14,6 +14,7 @@ use rustc_middle::middle::resolve_bound_vars::Set1;
1414use rustc_middle:: mir:: visit:: * ;
1515use rustc_middle:: mir:: * ;
1616use rustc_middle:: ty:: { self , TyCtxt } ;
17+ use rustc_mir_dataflow:: Analysis ;
1718use tracing:: { debug, instrument, trace} ;
1819
1920pub ( super ) struct SsaLocals {
@@ -391,3 +392,77 @@ impl StorageLiveLocals {
391392 matches ! ( self . storage_live[ local] , Set1 :: One ( _) )
392393 }
393394}
395+
396+ /// A dataflow analysis that tracks locals that are maybe uninitialized.
397+ ///
398+ /// This is a simpler analysis than `MaybeUninitializedPlaces`, because it does not track
399+ /// individual fields.
400+ pub ( crate ) struct MaybeUninitializedLocals ;
401+
402+ impl MaybeUninitializedLocals {
403+ pub ( crate ) fn new ( ) -> Self {
404+ Self { }
405+ }
406+ }
407+
408+ impl < ' tcx > Analysis < ' tcx > for MaybeUninitializedLocals {
409+ type Domain = DenseBitSet < Local > ;
410+
411+ const NAME : & ' static str = "maybe_uninit_locals" ;
412+
413+ fn bottom_value ( & self , body : & Body < ' tcx > ) -> Self :: Domain {
414+ // bottom = all locals are initialized.
415+ DenseBitSet :: new_empty ( body. local_decls . len ( ) )
416+ }
417+
418+ fn initialize_start_block ( & self , body : & Body < ' tcx > , state : & mut Self :: Domain ) {
419+ // All locals start as uninitialized...
420+ state. insert_all ( ) ;
421+ // ...except for arguments, which are definitely initialized.
422+ for arg in body. args_iter ( ) {
423+ state. remove ( arg) ;
424+ }
425+ }
426+
427+ fn apply_primary_statement_effect (
428+ & mut self ,
429+ state : & mut Self :: Domain ,
430+ statement : & Statement < ' tcx > ,
431+ _location : Location ,
432+ ) {
433+ match statement. kind {
434+ // An assignment makes a local initialized.
435+ StatementKind :: Assign ( box ( place, _) ) => {
436+ if let Some ( local) = place. as_local ( ) {
437+ state. remove ( local) ;
438+ }
439+ }
440+ // Deinit makes the local uninitialized.
441+ StatementKind :: Deinit ( box place) => {
442+ // A deinit makes a local uninitialized.
443+ if let Some ( local) = place. as_local ( ) {
444+ state. insert ( local) ;
445+ }
446+ }
447+ // Storage{Live,Dead} makes a local uninitialized.
448+ StatementKind :: StorageLive ( local) | StatementKind :: StorageDead ( local) => {
449+ state. insert ( local) ;
450+ }
451+ _ => { }
452+ }
453+ }
454+
455+ fn apply_call_return_effect (
456+ & mut self ,
457+ state : & mut Self :: Domain ,
458+ _block : BasicBlock ,
459+ return_places : CallReturnPlaces < ' _ , ' tcx > ,
460+ ) {
461+ // The return place of a call is initialized.
462+ return_places. for_each ( |place| {
463+ if let Some ( local) = place. as_local ( ) {
464+ state. remove ( local) ;
465+ }
466+ } ) ;
467+ }
468+ }
0 commit comments