@@ -699,31 +699,52 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
699
699
result
700
700
}
701
701
702
+ /// If `ty.needs_drop(...)` returns `true`, then `ty` is definitely
703
+ /// non-copy and *might* have a destructor attached; if it returns
704
+ /// `false`, then `ty` definitely has no destructor (i.e. no drop glue).
705
+ ///
706
+ /// (Note that this implies that if `ty` has a destructor attached,
707
+ /// then `needs_drop` will definitely return `true` for `ty`.)
702
708
#[ inline]
703
- pub fn may_drop ( & ' tcx self , tcx : TyCtxt < ' a , ' tcx , ' tcx > ) -> bool {
704
- if self . flags . get ( ) . intersects ( TypeFlags :: MAY_DROP_CACHED ) {
705
- return self . flags . get ( ) . intersects ( TypeFlags :: MAY_DROP ) ;
709
+ pub fn needs_drop ( & ' tcx self , tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
710
+ param_env : & ty:: ParameterEnvironment < ' tcx > ) -> bool {
711
+ if self . flags . get ( ) . intersects ( TypeFlags :: NEEDS_DROP_CACHED ) {
712
+ return self . flags . get ( ) . intersects ( TypeFlags :: NEEDS_DROP ) ;
706
713
}
707
714
708
- self . may_drop_inner ( tcx, & mut FxHashSet ( ) )
715
+ self . needs_drop_uncached ( tcx, param_env , & mut FxHashSet ( ) )
709
716
}
710
717
711
- fn may_drop_inner ( & ' tcx self ,
712
- tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
713
- visited : & mut FxHashSet < Ty < ' tcx > > )
714
- -> bool {
715
- if self . flags . get ( ) . intersects ( TypeFlags :: MAY_DROP_CACHED ) {
716
- return self . flags . get ( ) . intersects ( TypeFlags :: MAY_DROP ) ;
718
+ fn needs_drop_inner ( & ' tcx self ,
719
+ tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
720
+ param_env : & ty:: ParameterEnvironment < ' tcx > ,
721
+ stack : & mut FxHashSet < Ty < ' tcx > > )
722
+ -> bool {
723
+ if self . flags . get ( ) . intersects ( TypeFlags :: NEEDS_DROP_CACHED ) {
724
+ return self . flags . get ( ) . intersects ( TypeFlags :: NEEDS_DROP ) ;
717
725
}
718
726
719
727
// This should be reported as an error by `check_representable`.
720
728
//
721
729
// Consider the type as not needing drop in the meanwhile to avoid
722
730
// further errors.
723
- if visited . replace ( self ) . is_some ( ) {
731
+ if let Some ( _ ) = stack . replace ( self ) {
724
732
return false ;
725
733
}
726
734
735
+ let needs_drop = self . needs_drop_uncached ( tcx, param_env, stack) ;
736
+
737
+ // "Pop" the cycle detection "stack".
738
+ stack. remove ( self ) ;
739
+
740
+ needs_drop
741
+ }
742
+
743
+ fn needs_drop_uncached ( & ' tcx self ,
744
+ tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
745
+ param_env : & ty:: ParameterEnvironment < ' tcx > ,
746
+ stack : & mut FxHashSet < Ty < ' tcx > > )
747
+ -> bool {
727
748
assert ! ( !self . needs_infer( ) ) ;
728
749
729
750
let result = match self . sty {
@@ -733,6 +754,21 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
733
754
ty:: TyFnDef ( ..) | ty:: TyFnPtr ( _) | ty:: TyChar |
734
755
ty:: TyRawPtr ( _) | ty:: TyRef ( ..) | ty:: TyStr => false ,
735
756
757
+ // Issue #22536: We first query type_moves_by_default. It sees a
758
+ // normalized version of the type, and therefore will definitely
759
+ // know whether the type implements Copy (and thus needs no
760
+ // cleanup/drop/zeroing) ...
761
+ _ if !self . moves_by_default ( tcx, param_env, DUMMY_SP ) => false ,
762
+
763
+ // ... (issue #22536 continued) but as an optimization, still use
764
+ // prior logic of asking for the structural "may drop".
765
+
766
+ // FIXME(#22815): Note that this is a conservative heuristic;
767
+ // it may report that the type "may drop" when actual type does
768
+ // not actually have a destructor associated with it. But since
769
+ // the type absolutely did not have the `Copy` bound attached
770
+ // (see above), it is sound to treat it as having a destructor.
771
+
736
772
// User destructors are the only way to have concrete drop types.
737
773
ty:: TyAdt ( def, _) if def. has_dtor ( tcx) => true ,
738
774
@@ -743,16 +779,16 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
743
779
744
780
// Structural recursion.
745
781
ty:: TyArray ( ty, _) | ty:: TySlice ( ty) => {
746
- ty. may_drop_inner ( tcx, visited )
782
+ ty. needs_drop_inner ( tcx, param_env , stack )
747
783
}
748
784
749
785
ty:: TyClosure ( def_id, ref substs) => {
750
786
substs. upvar_tys ( def_id, tcx)
751
- . any ( |ty| ty. may_drop_inner ( tcx, visited ) )
787
+ . any ( |ty| ty. needs_drop_inner ( tcx, param_env , stack ) )
752
788
}
753
789
754
790
ty:: TyTuple ( ref tys, _) => {
755
- tys. iter ( ) . any ( |ty| ty. may_drop_inner ( tcx, visited ) )
791
+ tys. iter ( ) . any ( |ty| ty. needs_drop_inner ( tcx, param_env , stack ) )
756
792
}
757
793
758
794
// unions don't have destructors regardless of the child types
@@ -761,17 +797,19 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
761
797
ty:: TyAdt ( def, substs) => {
762
798
def. variants . iter ( ) . any ( |v| {
763
799
v. fields . iter ( ) . any ( |f| {
764
- f. ty ( tcx, substs) . may_drop_inner ( tcx, visited )
800
+ f. ty ( tcx, substs) . needs_drop_inner ( tcx, param_env , stack )
765
801
} )
766
802
} )
767
803
}
768
804
} ;
769
805
770
- self . flags . set ( self . flags . get ( ) | if result {
771
- TypeFlags :: MAY_DROP_CACHED | TypeFlags :: MAY_DROP
772
- } else {
773
- TypeFlags :: MAY_DROP_CACHED
774
- } ) ;
806
+ if !self . has_param_types ( ) && !self . has_self_ty ( ) {
807
+ self . flags . set ( self . flags . get ( ) | if result {
808
+ TypeFlags :: NEEDS_DROP_CACHED | TypeFlags :: NEEDS_DROP
809
+ } else {
810
+ TypeFlags :: NEEDS_DROP_CACHED
811
+ } ) ;
812
+ }
775
813
776
814
result
777
815
}
0 commit comments