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