@@ -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 , StdEntry } ;
39
+ use rustc_data_structures:: fx:: { FxHashMap , FxIndexSet , StdEntry } ;
40
40
use rustc_data_structures:: stack:: ensure_sufficient_stack;
41
41
use rustc_index:: bit_set:: BitSet ;
42
42
use rustc_index:: IndexVec ;
@@ -796,7 +796,52 @@ impl<'tcx> Map<'tcx> {
796
796
self . locals [ local] = Some ( place) ;
797
797
}
798
798
799
- PlaceCollector { tcx, body, map : self } . visit_body ( body) ;
799
+ // Collect syntactic places and assignments between them.
800
+ let mut collector =
801
+ PlaceCollector { tcx, body, map : self , assignments : Default :: default ( ) } ;
802
+ collector. visit_body ( body) ;
803
+ let PlaceCollector { mut assignments, .. } = collector;
804
+
805
+ // Just collecting syntactic places is not enough. We may need to propagate this pattern:
806
+ // _1 = (const 5u32, const 13i64);
807
+ // _2 = _1;
808
+ // _3 = (_2.0 as u32);
809
+ //
810
+ // `_1.0` does not appear, but we still need to track it. This is achieved by propagating
811
+ // projections from assignments. We recorded an assignment between `_2` and `_1`, so we
812
+ // want `_1` and `_2` to have the same sub-places.
813
+ //
814
+ // This is what this fixpoint loop does. While we are still creating places, run through
815
+ // all the assignments, and register places for children.
816
+ let mut num_places = 0 ;
817
+ while num_places < self . places . len ( ) {
818
+ num_places = self . places . len ( ) ;
819
+
820
+ for assign in 0 .. {
821
+ let Some ( & ( lhs, rhs) ) = assignments. get_index ( assign) else { break } ;
822
+
823
+ // Mirror children from `lhs` in `rhs`.
824
+ let mut child = self . places [ lhs] . first_child ;
825
+ while let Some ( lhs_child) = child {
826
+ let PlaceInfo { ty, proj_elem, next_sibling, .. } = self . places [ lhs_child] ;
827
+ let rhs_child =
828
+ self . register_place ( ty, rhs, proj_elem. expect ( "child is not a projection" ) ) ;
829
+ assignments. insert ( ( lhs_child, rhs_child) ) ;
830
+ child = next_sibling;
831
+ }
832
+
833
+ // Conversely, mirror children from `rhs` in `lhs`.
834
+ let mut child = self . places [ rhs] . first_child ;
835
+ while let Some ( rhs_child) = child {
836
+ let PlaceInfo { ty, proj_elem, next_sibling, .. } = self . places [ rhs_child] ;
837
+ let lhs_child =
838
+ self . register_place ( ty, lhs, proj_elem. expect ( "child is not a projection" ) ) ;
839
+ assignments. insert ( ( lhs_child, rhs_child) ) ;
840
+ child = next_sibling;
841
+ }
842
+ }
843
+ }
844
+ drop ( assignments) ;
800
845
801
846
// Create values for places whose type have scalar layout.
802
847
let param_env = tcx. param_env_reveal_all_normalized ( body. source . def_id ( ) ) ;
@@ -879,17 +924,14 @@ struct PlaceCollector<'a, 'b, 'tcx> {
879
924
tcx : TyCtxt < ' tcx > ,
880
925
body : & ' b Body < ' tcx > ,
881
926
map : & ' a mut Map < ' tcx > ,
927
+ assignments : FxIndexSet < ( PlaceIndex , PlaceIndex ) > ,
882
928
}
883
929
884
- impl < ' tcx > Visitor < ' tcx > for PlaceCollector < ' _ , ' _ , ' tcx > {
930
+ impl < ' tcx > PlaceCollector < ' _ , ' _ , ' tcx > {
885
931
#[ tracing:: instrument( level = "trace" , skip( self ) ) ]
886
- fn visit_place ( & mut self , place : & Place < ' tcx > , ctxt : PlaceContext , _: Location ) {
887
- if !ctxt. is_use ( ) {
888
- return ;
889
- }
890
-
932
+ fn register_place ( & mut self , place : Place < ' tcx > ) -> Option < PlaceIndex > {
891
933
// Create a place for this projection.
892
- let Some ( mut place_index) = self . map . locals [ place. local ] else { return } ;
934
+ let mut place_index = self . map . locals [ place. local ] ? ;
893
935
let mut ty = PlaceTy :: from_ty ( self . body . local_decls [ place. local ] . ty ) ;
894
936
tracing:: trace!( ?place_index, ?ty) ;
895
937
@@ -903,7 +945,7 @@ impl<'tcx> Visitor<'tcx> for PlaceCollector<'_, '_, 'tcx> {
903
945
}
904
946
905
947
for proj in place. projection {
906
- let Ok ( track_elem) = proj. try_into ( ) else { return } ;
948
+ let track_elem = proj. try_into ( ) . ok ( ) ? ;
907
949
ty = ty. projection_ty ( self . tcx , proj) ;
908
950
place_index = self . map . register_place ( ty. ty , place_index, track_elem) ;
909
951
tracing:: trace!( ?proj, ?place_index, ?ty) ;
@@ -917,6 +959,63 @@ impl<'tcx> Visitor<'tcx> for PlaceCollector<'_, '_, 'tcx> {
917
959
self . map . register_place ( discriminant_ty, place_index, TrackElem :: Discriminant ) ;
918
960
}
919
961
}
962
+
963
+ Some ( place_index)
964
+ }
965
+ }
966
+
967
+ impl < ' tcx > Visitor < ' tcx > for PlaceCollector < ' _ , ' _ , ' tcx > {
968
+ #[ tracing:: instrument( level = "trace" , skip( self ) ) ]
969
+ fn visit_place ( & mut self , place : & Place < ' tcx > , ctxt : PlaceContext , _: Location ) {
970
+ if !ctxt. is_use ( ) {
971
+ return ;
972
+ }
973
+
974
+ self . register_place ( * place) ;
975
+ }
976
+
977
+ fn visit_assign ( & mut self , lhs : & Place < ' tcx > , rhs : & Rvalue < ' tcx > , location : Location ) {
978
+ self . super_assign ( lhs, rhs, location) ;
979
+
980
+ match rhs {
981
+ Rvalue :: Use ( Operand :: Move ( rhs) | Operand :: Copy ( rhs) ) | Rvalue :: CopyForDeref ( rhs) => {
982
+ let Some ( lhs) = self . register_place ( * lhs) else { return } ;
983
+ let Some ( rhs) = self . register_place ( * rhs) else { return } ;
984
+ self . assignments . insert ( ( lhs, rhs) ) ;
985
+ }
986
+ Rvalue :: Aggregate ( kind, fields) => {
987
+ let Some ( mut lhs) = self . register_place ( * lhs) else { return } ;
988
+ match * * kind {
989
+ // Do not propagate unions.
990
+ AggregateKind :: Adt ( _, _, _, _, Some ( _) ) => return ,
991
+ AggregateKind :: Adt ( _, variant, _, _, None ) => {
992
+ let ty = self . map . places [ lhs] . ty ;
993
+ if ty. is_enum ( ) {
994
+ lhs = self . map . register_place ( ty, lhs, TrackElem :: Variant ( variant) ) ;
995
+ }
996
+ }
997
+ AggregateKind :: RawPtr ( ..)
998
+ | AggregateKind :: Array ( _)
999
+ | AggregateKind :: Tuple
1000
+ | AggregateKind :: Closure ( ..)
1001
+ | AggregateKind :: Coroutine ( ..)
1002
+ | AggregateKind :: CoroutineClosure ( ..) => { }
1003
+ }
1004
+ for ( index, field) in fields. iter_enumerated ( ) {
1005
+ if let Some ( rhs) = field. place ( )
1006
+ && let Some ( rhs) = self . register_place ( rhs)
1007
+ {
1008
+ let lhs = self . map . register_place (
1009
+ self . map . places [ rhs] . ty ,
1010
+ lhs,
1011
+ TrackElem :: Field ( index) ,
1012
+ ) ;
1013
+ self . assignments . insert ( ( lhs, rhs) ) ;
1014
+ }
1015
+ }
1016
+ }
1017
+ _ => { }
1018
+ }
920
1019
}
921
1020
}
922
1021
0 commit comments