@@ -33,8 +33,9 @@ fn is_stable(place: PlaceRef<'_>) -> bool {
3333 } )
3434}
3535
36- /// Determine whether this type may be a reference (or box), and thus needs retagging.
37- fn may_be_reference ( ty : Ty < ' _ > ) -> bool {
36+ /// Determine whether this type may contain a reference (or box), and thus needs retagging.
37+ /// We will only recurse `depth` times into Tuples/ADTs to bound the cost of this.
38+ fn may_contain_reference < ' tcx > ( ty : Ty < ' tcx > , depth : u32 , tcx : TyCtxt < ' tcx > ) -> bool {
3839 match ty. kind ( ) {
3940 // Primitive types that are not references
4041 ty:: Bool
@@ -50,8 +51,20 @@ fn may_be_reference(ty: Ty<'_>) -> bool {
5051 // References
5152 ty:: Ref ( ..) => true ,
5253 ty:: Adt ( ..) if ty. is_box ( ) => true ,
53- // Compound types are not references
54- ty:: Array ( ..) | ty:: Slice ( ..) | ty:: Tuple ( ..) | ty:: Adt ( ..) => false ,
54+ // Compound types: recurse
55+ ty:: Array ( ty, _) | ty:: Slice ( ty) => {
56+ // This does not branch so we keep the depth the same.
57+ may_contain_reference ( * ty, depth, tcx)
58+ }
59+ ty:: Tuple ( tys) => {
60+ depth == 0 || tys. iter ( ) . any ( |ty| may_contain_reference ( ty, depth - 1 , tcx) )
61+ }
62+ ty:: Adt ( adt, subst) => {
63+ depth == 0
64+ || adt. variants ( ) . iter ( ) . any ( |v| {
65+ v. fields . iter ( ) . any ( |f| may_contain_reference ( f. ty ( tcx, subst) , depth - 1 , tcx) )
66+ } )
67+ }
5568 // Conservative fallback
5669 _ => true ,
5770 }
@@ -83,7 +96,7 @@ impl<'tcx> MirPass<'tcx> for AddRetag {
8396 // FIXME: Instead of giving up for unstable places, we should introduce
8497 // a temporary and retag on that.
8598 is_stable ( place. as_ref ( ) )
86- && may_be_reference ( place. ty ( & * local_decls, tcx) . ty )
99+ && may_contain_reference ( place. ty ( & * local_decls, tcx) . ty , /*depth*/ 3 , tcx )
87100 && is_not_temp ( & local_decls[ place. local ] )
88101 } ;
89102 let place_base_raw = |place : & Place < ' tcx > | {
0 commit comments