@@ -69,10 +69,11 @@ use rustc_middle::ty::{
69
69
} ;
70
70
use rustc_middle:: { bug, span_bug} ;
71
71
use rustc_mir_dataflow:: impls:: {
72
- MaybeBorrowedLocals , MaybeLiveLocals , MaybeRequiresStorage , MaybeStorageLive ,
73
- always_storage_live_locals,
72
+ MaybeBorrowedLocals , MaybeInitializedPlaces , MaybeLiveLocals , MaybeRequiresStorage ,
73
+ MaybeStorageLive , always_storage_live_locals,
74
74
} ;
75
- use rustc_mir_dataflow:: { Analysis , Results , ResultsVisitor } ;
75
+ use rustc_mir_dataflow:: move_paths:: MoveData ;
76
+ use rustc_mir_dataflow:: { self , Analysis , MaybeReachable , Results , ResultsVisitor } ;
76
77
use rustc_span:: def_id:: { DefId , LocalDefId } ;
77
78
use rustc_span:: { Span , sym} ;
78
79
use rustc_target:: spec:: PanicStrategy ;
@@ -633,6 +634,12 @@ struct LivenessInfo {
633
634
/// Which locals are live across any suspension point.
634
635
saved_locals : CoroutineSavedLocals ,
635
636
637
+ /// Which locals are live *and* initialized across any suspension point.
638
+ ///
639
+ /// A local that is live but is not initialized (i.e. it has been moved out of) does
640
+ /// not need to be accounted for in auto trait checking.
641
+ init_locals : DenseBitSet < Local > ,
642
+
636
643
/// The set of saved locals live at each suspension point.
637
644
live_locals_at_suspension_points : Vec < DenseBitSet < CoroutineSavedLocal > > ,
638
645
@@ -686,10 +693,18 @@ fn locals_live_across_suspend_points<'tcx>(
686
693
let mut liveness =
687
694
MaybeLiveLocals . iterate_to_fixpoint ( tcx, body, Some ( "coroutine" ) ) . into_results_cursor ( body) ;
688
695
696
+ let move_data = MoveData :: gather_moves ( body, tcx, |_| true ) ;
697
+
698
+ // Calculate the set of locals which are initialized
699
+ let mut inits = MaybeInitializedPlaces :: new ( tcx, body, & move_data)
700
+ . iterate_to_fixpoint ( tcx, body, Some ( "coroutine" ) )
701
+ . into_results_cursor ( body) ;
702
+
689
703
let mut storage_liveness_map = IndexVec :: from_elem ( None , & body. basic_blocks ) ;
690
704
let mut live_locals_at_suspension_points = Vec :: new ( ) ;
691
705
let mut source_info_at_suspension_points = Vec :: new ( ) ;
692
706
let mut live_locals_at_any_suspension_point = DenseBitSet :: new_empty ( body. local_decls . len ( ) ) ;
707
+ let mut init_locals_at_any_suspension_point = DenseBitSet :: new_empty ( body. local_decls . len ( ) ) ;
693
708
694
709
for ( block, data) in body. basic_blocks . iter_enumerated ( ) {
695
710
if let TerminatorKind :: Yield { .. } = data. terminator ( ) . kind {
@@ -727,12 +742,26 @@ fn locals_live_across_suspend_points<'tcx>(
727
742
// The coroutine argument is ignored.
728
743
live_locals. remove ( SELF_ARG ) ;
729
744
730
- debug ! ( "loc = {:?}, live_locals = {:?}" , loc, live_locals) ;
745
+ inits. seek_to_block_end ( block) ;
746
+ let mut init_locals: DenseBitSet < _ > = DenseBitSet :: new_empty ( body. local_decls . len ( ) ) ;
747
+ if let MaybeReachable :: Reachable ( bitset) = inits. get ( ) {
748
+ for move_path_index in bitset. iter ( ) {
749
+ if let Some ( local) = move_data. move_paths [ move_path_index] . place . as_local ( ) {
750
+ init_locals. insert ( local) ;
751
+ }
752
+ }
753
+ }
754
+ init_locals. intersect ( & live_locals) ;
755
+
756
+ debug ! (
757
+ "loc = {:?}, live_locals = {:?}, init_locals = {:?}" ,
758
+ loc, live_locals, init_locals
759
+ ) ;
731
760
732
761
// Add the locals live at this suspension point to the set of locals which live across
733
762
// any suspension points
734
763
live_locals_at_any_suspension_point. union ( & live_locals) ;
735
-
764
+ init_locals_at_any_suspension_point . union ( & init_locals ) ;
736
765
live_locals_at_suspension_points. push ( live_locals) ;
737
766
source_info_at_suspension_points. push ( data. terminator ( ) . source_info ) ;
738
767
}
@@ -757,6 +786,7 @@ fn locals_live_across_suspend_points<'tcx>(
757
786
758
787
LivenessInfo {
759
788
saved_locals,
789
+ init_locals : init_locals_at_any_suspension_point,
760
790
live_locals_at_suspension_points,
761
791
source_info_at_suspension_points,
762
792
storage_conflicts,
@@ -929,6 +959,7 @@ fn compute_layout<'tcx>(
929
959
) {
930
960
let LivenessInfo {
931
961
saved_locals,
962
+ init_locals,
932
963
live_locals_at_suspension_points,
933
964
source_info_at_suspension_points,
934
965
storage_conflicts,
@@ -950,6 +981,9 @@ fn compute_layout<'tcx>(
950
981
// this code runs on pre-cleanup MIR, and `ignore_for_traits = false` is the safer
951
982
// default.
952
983
let ignore_for_traits = match decl. local_info {
984
+ // If only the storage is required to be live, but local is not initialized,
985
+ // then we can ignore such type for auto trait purposes.
986
+ _ if !init_locals. contains ( local) => true ,
953
987
// Do not include raw pointers created from accessing `static` items, as those could
954
988
// well be re-created by another access to the same static.
955
989
ClearCrossCrate :: Set ( box LocalInfo :: StaticRef { is_thread_local, .. } ) => {
0 commit comments