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