33use rustc_data_structures:: fx:: FxHashSet ;
44use rustc_hir:: def_id:: DefId ;
55use rustc_middle:: ty:: subst:: Subst ;
6+ use rustc_middle:: ty:: subst:: SubstsRef ;
67use rustc_middle:: ty:: util:: { needs_drop_components, AlwaysRequiresDrop } ;
78use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
89use rustc_session:: Limit ;
@@ -12,7 +13,7 @@ type NeedsDropResult<T> = Result<T, AlwaysRequiresDrop>;
1213
1314fn needs_drop_raw < ' tcx > ( tcx : TyCtxt < ' tcx > , query : ty:: ParamEnvAnd < ' tcx , Ty < ' tcx > > ) -> bool {
1415 let adt_components =
15- move |adt_def : & ty:: AdtDef | tcx. adt_drop_tys ( adt_def. did ) . map ( |tys| tys. iter ( ) ) ;
16+ move |adt_def : & ty:: AdtDef , _ | tcx. adt_drop_tys ( adt_def. did ) . map ( |tys| tys. iter ( ) ) ;
1617
1718 // If we don't know a type doesn't need drop, for example if it's a type
1819 // parameter without a `Copy` bound, then we conservatively return that it
@@ -28,8 +29,9 @@ fn has_significant_drop_raw<'tcx>(
2829 tcx : TyCtxt < ' tcx > ,
2930 query : ty:: ParamEnvAnd < ' tcx , Ty < ' tcx > > ,
3031) -> bool {
31- let significant_drop_fields =
32- move |adt_def : & ty:: AdtDef | tcx. adt_significant_drop_tys ( adt_def. did ) . map ( |tys| tys. iter ( ) ) ;
32+ let significant_drop_fields = move |adt_def : & ty:: AdtDef , _| {
33+ tcx. adt_significant_drop_tys ( adt_def. did ) . map ( |tys| tys. iter ( ) )
34+ } ;
3335 let res = NeedsDropTypes :: new ( tcx, query. param_env , query. value , significant_drop_fields)
3436 . next ( )
3537 . is_some ( ) ;
@@ -74,7 +76,7 @@ impl<'tcx, F> NeedsDropTypes<'tcx, F> {
7476
7577impl < ' tcx , F , I > Iterator for NeedsDropTypes < ' tcx , F >
7678where
77- F : Fn ( & ty:: AdtDef ) -> NeedsDropResult < I > ,
79+ F : Fn ( & ty:: AdtDef , SubstsRef < ' tcx > ) -> NeedsDropResult < I > ,
7880 I : Iterator < Item = Ty < ' tcx > > ,
7981{
8082 type Item = NeedsDropResult < Ty < ' tcx > > ;
@@ -138,7 +140,7 @@ where
138140 // `ManuallyDrop`. If it's a struct or enum without a `Drop`
139141 // impl then check whether the field types need `Drop`.
140142 ty:: Adt ( adt_def, substs) => {
141- let tys = match ( self . adt_components ) ( adt_def) {
143+ let tys = match ( self . adt_components ) ( adt_def, substs ) {
142144 Err ( e) => return Some ( Err ( e) ) ,
143145 Ok ( tys) => tys,
144146 } ;
@@ -171,22 +173,44 @@ where
171173 }
172174}
173175
176+ enum DtorType {
177+ /// Type has a `Drop` but it is considered insignificant.
178+ /// Check the query `adt_significant_drop_tys` for understanding
179+ /// "significant" / "insignificant".
180+ Insignificant ,
181+
182+ /// Type has a `Drop` implentation.
183+ Significant ,
184+ }
185+
174186// This is a helper function for `adt_drop_tys` and `adt_significant_drop_tys`.
175187// Depending on the implentation of `adt_has_dtor`, it is used to check if the
176188// ADT has a destructor or if the ADT only has a significant destructor. For
177189// understanding significant destructor look at `adt_significant_drop_tys`.
178- fn adt_drop_tys_helper (
179- tcx : TyCtxt < ' _ > ,
190+ fn adt_drop_tys_helper < ' tcx > (
191+ tcx : TyCtxt < ' tcx > ,
180192 def_id : DefId ,
181- adt_has_dtor : impl Fn ( & ty:: AdtDef ) -> bool ,
182- ) -> Result < & ty:: List < Ty < ' _ > > , AlwaysRequiresDrop > {
183- let adt_components = move |adt_def : & ty:: AdtDef | {
193+ adt_has_dtor : impl Fn ( & ty:: AdtDef ) -> Option < DtorType > ,
194+ ) -> Result < & ty:: List < Ty < ' tcx > > , AlwaysRequiresDrop > {
195+ let adt_components = move |adt_def : & ty:: AdtDef , substs : SubstsRef < ' tcx > | {
184196 if adt_def. is_manually_drop ( ) {
185197 debug ! ( "adt_drop_tys: `{:?}` is manually drop" , adt_def) ;
186198 return Ok ( Vec :: new ( ) . into_iter ( ) ) ;
187- } else if adt_has_dtor ( adt_def) {
188- debug ! ( "adt_drop_tys: `{:?}` implements `Drop`" , adt_def) ;
189- return Err ( AlwaysRequiresDrop ) ;
199+ } else if let Some ( dtor_info) = adt_has_dtor ( adt_def) {
200+ match dtor_info {
201+ DtorType :: Significant => {
202+ debug ! ( "adt_drop_tys: `{:?}` implements `Drop`" , adt_def) ;
203+ return Err ( AlwaysRequiresDrop ) ;
204+ }
205+ DtorType :: Insignificant => {
206+ debug ! ( "adt_drop_tys: `{:?}` drop is insignificant" , adt_def) ;
207+
208+ // Since the destructor is insignificant, we just want to make sure all of
209+ // the passed in type parameters are also insignificant.
210+ // Eg: Vec<T> dtor is insignificant when T=i32 but significant when T=Mutex.
211+ return Ok ( substs. types ( ) . collect :: < Vec < Ty < ' _ > > > ( ) . into_iter ( ) ) ;
212+ }
213+ }
190214 } else if adt_def. is_union ( ) {
191215 debug ! ( "adt_drop_tys: `{:?}` is a union" , adt_def) ;
192216 return Ok ( Vec :: new ( ) . into_iter ( ) ) ;
@@ -204,7 +228,10 @@ fn adt_drop_tys_helper(
204228}
205229
206230fn adt_drop_tys ( tcx : TyCtxt < ' _ > , def_id : DefId ) -> Result < & ty:: List < Ty < ' _ > > , AlwaysRequiresDrop > {
207- let adt_has_dtor = |adt_def : & ty:: AdtDef | adt_def. destructor ( tcx) . is_some ( ) ;
231+ // This is for the "needs_drop" query, that considers all `Drop` impls, therefore all dtors are
232+ // significant.
233+ let adt_has_dtor =
234+ |adt_def : & ty:: AdtDef | adt_def. destructor ( tcx) . map ( |_| DtorType :: Significant ) ;
208235 adt_drop_tys_helper ( tcx, def_id, adt_has_dtor)
209236}
210237
@@ -213,10 +240,22 @@ fn adt_significant_drop_tys(
213240 def_id : DefId ,
214241) -> Result < & ty:: List < Ty < ' _ > > , AlwaysRequiresDrop > {
215242 let adt_has_dtor = |adt_def : & ty:: AdtDef | {
216- adt_def
217- . destructor ( tcx)
218- . map ( |dtor| !tcx. has_attr ( dtor. did , sym:: rustc_insignificant_dtor) )
219- . unwrap_or ( false )
243+ let is_marked_insig = tcx. has_attr ( adt_def. did , sym:: rustc_insignificant_dtor) ;
244+ if is_marked_insig {
245+ // In some cases like `std::collections::HashMap` where the struct is a wrapper around
246+ // a type that is a Drop type, and the wrapped type (eg: `hashbrown::HashMap`) lies
247+ // outside stdlib, we might choose to still annotate the the wrapper (std HashMap) with
248+ // `rustc_insignificant_dtor`, even if the type itself doesn't have a `Drop` impl.
249+ Some ( DtorType :: Insignificant )
250+ } else if adt_def. destructor ( tcx) . is_some ( ) {
251+ // There is a Drop impl and the type isn't marked insignificant, therefore Drop must be
252+ // significant.
253+ Some ( DtorType :: Significant )
254+ } else {
255+ // No destructor found nor the type is annotated with `rustc_insignificant_dtor`, we
256+ // treat this as the simple case of Drop impl for type.
257+ None
258+ }
220259 } ;
221260 adt_drop_tys_helper ( tcx, def_id, adt_has_dtor)
222261}
0 commit comments