@@ -21,7 +21,7 @@ use ty::fold::TypeVisitor;
2121use ty:: layout:: { Layout , LayoutError } ;
2222use ty:: TypeVariants :: * ;
2323use util:: common:: ErrorReported ;
24- use util:: nodemap:: FxHashMap ;
24+ use util:: nodemap:: { FxHashMap , FxHashSet } ;
2525use middle:: lang_items;
2626
2727use rustc_const_math:: { ConstInt , ConstIsize , ConstUsize } ;
@@ -699,6 +699,83 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
699699 result
700700 }
701701
702+ #[ 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 ) ;
706+ }
707+
708+ self . may_drop_inner ( tcx, & mut FxHashSet ( ) )
709+ }
710+
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 ) ;
717+ }
718+
719+ // This should be reported as an error by `check_representable`.
720+ //
721+ // Consider the type as not needing drop in the meanwhile to avoid
722+ // further errors.
723+ if visited. replace ( self ) . is_some ( ) {
724+ return false ;
725+ }
726+
727+ assert ! ( !self . needs_infer( ) ) ;
728+
729+ let result = match self . sty {
730+ // Fast-path for primitive types
731+ ty:: TyInfer ( ty:: FreshIntTy ( _) ) | ty:: TyInfer ( ty:: FreshFloatTy ( _) ) |
732+ ty:: TyBool | ty:: TyInt ( _) | ty:: TyUint ( _) | ty:: TyFloat ( _) | ty:: TyNever |
733+ ty:: TyFnDef ( ..) | ty:: TyFnPtr ( _) | ty:: TyChar |
734+ ty:: TyRawPtr ( _) | ty:: TyRef ( ..) | ty:: TyStr => false ,
735+
736+ // User destructors are the only way to have concrete drop types.
737+ ty:: TyAdt ( def, _) if def. has_dtor ( tcx) => true ,
738+
739+ // Can refer to a type which may drop.
740+ // FIXME(eddyb) check this against a ParameterEnvironment.
741+ ty:: TyDynamic ( ..) | ty:: TyProjection ( ..) | ty:: TyParam ( _) |
742+ ty:: TyAnon ( ..) | ty:: TyInfer ( _) | ty:: TyError => true ,
743+
744+ // Structural recursion.
745+ ty:: TyArray ( ty, _) | ty:: TySlice ( ty) => {
746+ ty. may_drop_inner ( tcx, visited)
747+ }
748+
749+ ty:: TyClosure ( def_id, ref substs) => {
750+ substs. upvar_tys ( def_id, tcx)
751+ . any ( |ty| ty. may_drop_inner ( tcx, visited) )
752+ }
753+
754+ ty:: TyTuple ( ref tys, _) => {
755+ tys. iter ( ) . any ( |ty| ty. may_drop_inner ( tcx, visited) )
756+ }
757+
758+ // unions don't have destructors regardless of the child types
759+ ty:: TyAdt ( def, _) if def. is_union ( ) => false ,
760+
761+ ty:: TyAdt ( def, substs) => {
762+ def. variants . iter ( ) . any ( |v| {
763+ v. fields . iter ( ) . any ( |f| {
764+ f. ty ( tcx, substs) . may_drop_inner ( tcx, visited)
765+ } )
766+ } )
767+ }
768+ } ;
769+
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+ } ) ;
775+
776+ result
777+ }
778+
702779 #[ inline]
703780 pub fn layout < ' lcx > ( & ' tcx self , infcx : & InferCtxt < ' a , ' tcx , ' lcx > )
704781 -> Result < & ' tcx Layout , LayoutError < ' tcx > > {
0 commit comments