@@ -14,6 +14,7 @@ use rustc_middle::middle::resolve_bound_vars::Set1;
14
14
use rustc_middle:: mir:: visit:: * ;
15
15
use rustc_middle:: mir:: * ;
16
16
use rustc_middle:: ty:: { self , TyCtxt } ;
17
+ use rustc_mir_dataflow:: Analysis ;
17
18
use tracing:: { debug, instrument, trace} ;
18
19
19
20
pub ( super ) struct SsaLocals {
@@ -391,3 +392,77 @@ impl StorageLiveLocals {
391
392
matches ! ( self . storage_live[ local] , Set1 :: One ( _) )
392
393
}
393
394
}
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