@@ -36,7 +36,7 @@ use std::fmt::{Debug, Formatter};
36
36
use std:: ops:: Range ;
37
37
38
38
use rustc_data_structures:: captures:: Captures ;
39
- use rustc_data_structures:: fx:: FxHashMap ;
39
+ use rustc_data_structures:: fx:: { FxHashMap , FxIndexSet } ;
40
40
use rustc_data_structures:: stack:: ensure_sufficient_stack;
41
41
use rustc_index:: bit_set:: BitSet ;
42
42
use rustc_index:: { IndexSlice , IndexVec } ;
@@ -760,7 +760,52 @@ impl<'tcx> Map<'tcx> {
760
760
tracing:: trace!( ?local, ?place) ;
761
761
}
762
762
763
- PlaceCollector { tcx, body, map : self } . visit_body ( body) ;
763
+ // Collect syntactic places and assignments between them.
764
+ let mut collector =
765
+ PlaceCollector { tcx, body, map : self , assignments : Default :: default ( ) } ;
766
+ collector. visit_body ( body) ;
767
+ let PlaceCollector { mut assignments, .. } = collector;
768
+
769
+ // Just collecting syntactic places is not enough. We may need to propagate this pattern:
770
+ // _1 = (const 5u32, const 13i64);
771
+ // _2 = _1;
772
+ // _3 = (_2.0 as u32);
773
+ //
774
+ // `_1.0` does not appear, but we still need to track it. This is achieved by propagating
775
+ // projections from assignments. We recorded an assignment between `_2` and `_1`, so we
776
+ // want `_1` and `_2` to have the same sub-places.
777
+ //
778
+ // This is what this fixpoint loop does. While we are still creating places, run through
779
+ // all the assignments, and register places for children.
780
+ let mut num_places = 0 ;
781
+ while num_places < self . places . len ( ) {
782
+ num_places = self . places . len ( ) ;
783
+
784
+ for assign in 0 .. {
785
+ let Some ( & ( lhs, rhs) ) = assignments. get_index ( assign) else { break } ;
786
+
787
+ // Mirror children from `lhs` in `rhs`.
788
+ let mut child = self . places [ lhs] . first_child ;
789
+ while let Some ( lhs_child) = child {
790
+ let PlaceInfo { ty, proj_elem, next_sibling, .. } = self . places [ lhs_child] ;
791
+ let rhs_child =
792
+ self . register_place ( ty, rhs, proj_elem. expect ( "child is not a projection" ) ) ;
793
+ assignments. insert ( ( lhs_child, rhs_child) ) ;
794
+ child = next_sibling;
795
+ }
796
+
797
+ // Conversely, mirror children from `rhs` in `lhs`.
798
+ let mut child = self . places [ rhs] . first_child ;
799
+ while let Some ( rhs_child) = child {
800
+ let PlaceInfo { ty, proj_elem, next_sibling, .. } = self . places [ rhs_child] ;
801
+ let lhs_child =
802
+ self . register_place ( ty, lhs, proj_elem. expect ( "child is not a projection" ) ) ;
803
+ assignments. insert ( ( lhs_child, rhs_child) ) ;
804
+ child = next_sibling;
805
+ }
806
+ }
807
+ }
808
+ drop ( assignments) ;
764
809
765
810
// Create values for places whose type have scalar layout.
766
811
let param_env = tcx. param_env_reveal_all_normalized ( body. source . def_id ( ) ) ;
@@ -845,17 +890,14 @@ struct PlaceCollector<'a, 'b, 'tcx> {
845
890
tcx : TyCtxt < ' tcx > ,
846
891
body : & ' b Body < ' tcx > ,
847
892
map : & ' a mut Map < ' tcx > ,
893
+ assignments : FxIndexSet < ( PlaceIndex , PlaceIndex ) > ,
848
894
}
849
895
850
- impl < ' tcx > Visitor < ' tcx > for PlaceCollector < ' _ , ' _ , ' tcx > {
896
+ impl < ' tcx > PlaceCollector < ' _ , ' _ , ' tcx > {
851
897
#[ tracing:: instrument( level = "trace" , skip( self ) ) ]
852
- fn visit_place ( & mut self , place : & Place < ' tcx > , ctxt : PlaceContext , _: Location ) {
853
- if !ctxt. is_use ( ) {
854
- return ;
855
- }
856
-
898
+ fn register_place ( & mut self , place : Place < ' tcx > ) -> Option < PlaceIndex > {
857
899
// Create a place for this projection.
858
- let Some ( mut place_index) = self . map . locals [ place. local ] else { return } ;
900
+ let mut place_index = self . map . locals [ place. local ] ? ;
859
901
let mut ty = PlaceTy :: from_ty ( self . body . local_decls [ place. local ] . ty ) ;
860
902
tracing:: trace!( ?place_index, ?ty) ;
861
903
@@ -869,7 +911,7 @@ impl<'tcx> Visitor<'tcx> for PlaceCollector<'_, '_, 'tcx> {
869
911
}
870
912
871
913
for proj in place. projection {
872
- let Ok ( track_elem) = proj. try_into ( ) else { return } ;
914
+ let track_elem = proj. try_into ( ) . ok ( ) ? ;
873
915
ty = ty. projection_ty ( self . tcx , proj) ;
874
916
place_index = self . map . register_place ( ty. ty , place_index, track_elem) ;
875
917
tracing:: trace!( ?proj, ?place_index, ?ty) ;
@@ -883,6 +925,63 @@ impl<'tcx> Visitor<'tcx> for PlaceCollector<'_, '_, 'tcx> {
883
925
self . map . register_place ( discriminant_ty, place_index, TrackElem :: Discriminant ) ;
884
926
}
885
927
}
928
+
929
+ Some ( place_index)
930
+ }
931
+ }
932
+
933
+ impl < ' tcx > Visitor < ' tcx > for PlaceCollector < ' _ , ' _ , ' tcx > {
934
+ #[ tracing:: instrument( level = "trace" , skip( self ) ) ]
935
+ fn visit_place ( & mut self , place : & Place < ' tcx > , ctxt : PlaceContext , _: Location ) {
936
+ if !ctxt. is_use ( ) {
937
+ return ;
938
+ }
939
+
940
+ self . register_place ( * place) ;
941
+ }
942
+
943
+ fn visit_assign ( & mut self , lhs : & Place < ' tcx > , rhs : & Rvalue < ' tcx > , location : Location ) {
944
+ self . super_assign ( lhs, rhs, location) ;
945
+
946
+ match rhs {
947
+ Rvalue :: Use ( Operand :: Move ( rhs) | Operand :: Copy ( rhs) ) | Rvalue :: CopyForDeref ( rhs) => {
948
+ let Some ( lhs) = self . register_place ( * lhs) else { return } ;
949
+ let Some ( rhs) = self . register_place ( * rhs) else { return } ;
950
+ self . assignments . insert ( ( lhs, rhs) ) ;
951
+ }
952
+ Rvalue :: Aggregate ( kind, fields) => {
953
+ let Some ( mut lhs) = self . register_place ( * lhs) else { return } ;
954
+ match * * kind {
955
+ // Do not propagate unions.
956
+ AggregateKind :: Adt ( _, _, _, _, Some ( _) ) => return ,
957
+ AggregateKind :: Adt ( _, variant, _, _, None ) => {
958
+ let ty = self . map . places [ lhs] . ty ;
959
+ if ty. is_enum ( ) {
960
+ lhs = self . map . register_place ( ty, lhs, TrackElem :: Variant ( variant) ) ;
961
+ }
962
+ }
963
+ AggregateKind :: RawPtr ( ..)
964
+ | AggregateKind :: Array ( _)
965
+ | AggregateKind :: Tuple
966
+ | AggregateKind :: Closure ( ..)
967
+ | AggregateKind :: Coroutine ( ..)
968
+ | AggregateKind :: CoroutineClosure ( ..) => { }
969
+ }
970
+ for ( index, field) in fields. iter_enumerated ( ) {
971
+ if let Some ( rhs) = field. place ( )
972
+ && let Some ( rhs) = self . register_place ( rhs)
973
+ {
974
+ let lhs = self . map . register_place (
975
+ self . map . places [ rhs] . ty ,
976
+ lhs,
977
+ TrackElem :: Field ( index) ,
978
+ ) ;
979
+ self . assignments . insert ( ( lhs, rhs) ) ;
980
+ }
981
+ }
982
+ }
983
+ _ => { }
984
+ }
886
985
}
887
986
}
888
987
0 commit comments