@@ -699,31 +699,52 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
699699 result
700700 }
701701
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`.)
702708 #[ 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 ) ;
706713 }
707714
708- self . may_drop_inner ( tcx, & mut FxHashSet ( ) )
715+ self . needs_drop_uncached ( tcx, param_env , & mut FxHashSet ( ) )
709716 }
710717
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 ) ;
717725 }
718726
719727 // This should be reported as an error by `check_representable`.
720728 //
721729 // Consider the type as not needing drop in the meanwhile to avoid
722730 // further errors.
723- if visited . replace ( self ) . is_some ( ) {
731+ if let Some ( _ ) = stack . replace ( self ) {
724732 return false ;
725733 }
726734
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 {
727748 assert ! ( !self . needs_infer( ) ) ;
728749
729750 let result = match self . sty {
@@ -733,6 +754,21 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
733754 ty:: TyFnDef ( ..) | ty:: TyFnPtr ( _) | ty:: TyChar |
734755 ty:: TyRawPtr ( _) | ty:: TyRef ( ..) | ty:: TyStr => false ,
735756
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+
736772 // User destructors are the only way to have concrete drop types.
737773 ty:: TyAdt ( def, _) if def. has_dtor ( tcx) => true ,
738774
@@ -743,16 +779,16 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
743779
744780 // Structural recursion.
745781 ty:: TyArray ( ty, _) | ty:: TySlice ( ty) => {
746- ty. may_drop_inner ( tcx, visited )
782+ ty. needs_drop_inner ( tcx, param_env , stack )
747783 }
748784
749785 ty:: TyClosure ( def_id, ref substs) => {
750786 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 ) )
752788 }
753789
754790 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 ) )
756792 }
757793
758794 // unions don't have destructors regardless of the child types
@@ -761,17 +797,19 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
761797 ty:: TyAdt ( def, substs) => {
762798 def. variants . iter ( ) . any ( |v| {
763799 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 )
765801 } )
766802 } )
767803 }
768804 } ;
769805
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+ }
775813
776814 result
777815 }
0 commit comments