@@ -36,7 +36,7 @@ use std::fmt::{Debug, Formatter};
3636use std:: ops:: Range ;
3737
3838use rustc_data_structures:: captures:: Captures ;
39- use rustc_data_structures:: fx:: { FxHashMap , StdEntry } ;
39+ use rustc_data_structures:: fx:: { FxHashMap , FxIndexSet , StdEntry } ;
4040use rustc_data_structures:: stack:: ensure_sufficient_stack;
4141use rustc_index:: bit_set:: BitSet ;
4242use rustc_index:: IndexVec ;
@@ -799,7 +799,52 @@ impl<'tcx> Map<'tcx> {
799799 self . locals [ local] = Some ( place) ;
800800 }
801801
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) ;
803848
804849 // Create values for places whose type have scalar layout.
805850 let param_env = tcx. param_env_reveal_all_normalized ( body. source . def_id ( ) ) ;
@@ -882,17 +927,14 @@ struct PlaceCollector<'a, 'b, 'tcx> {
882927 tcx : TyCtxt < ' tcx > ,
883928 body : & ' b Body < ' tcx > ,
884929 map : & ' a mut Map < ' tcx > ,
930+ assignments : FxIndexSet < ( PlaceIndex , PlaceIndex ) > ,
885931}
886932
887- impl < ' tcx > Visitor < ' tcx > for PlaceCollector < ' _ , ' _ , ' tcx > {
933+ impl < ' tcx > PlaceCollector < ' _ , ' _ , ' tcx > {
888934 #[ 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 > {
894936 // 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 ] ? ;
896938 let mut ty = PlaceTy :: from_ty ( self . body . local_decls [ place. local ] . ty ) ;
897939 tracing:: trace!( ?place_index, ?ty) ;
898940
@@ -906,7 +948,7 @@ impl<'tcx> Visitor<'tcx> for PlaceCollector<'_, '_, 'tcx> {
906948 }
907949
908950 for proj in place. projection {
909- let Ok ( track_elem) = proj. try_into ( ) else { return } ;
951+ let track_elem = proj. try_into ( ) . ok ( ) ? ;
910952 ty = ty. projection_ty ( self . tcx , proj) ;
911953 place_index = self . map . register_place ( ty. ty , place_index, track_elem) ;
912954 tracing:: trace!( ?proj, ?place_index, ?ty) ;
@@ -920,6 +962,63 @@ impl<'tcx> Visitor<'tcx> for PlaceCollector<'_, '_, 'tcx> {
920962 self . map . register_place ( discriminant_ty, place_index, TrackElem :: Discriminant ) ;
921963 }
922964 }
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+ }
9231022 }
9241023}
9251024
0 commit comments