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