3
3
use rustc_data_structures:: fx:: FxHashSet ;
4
4
use rustc_hir:: def_id:: DefId ;
5
5
use rustc_middle:: ty:: subst:: Subst ;
6
+ use rustc_middle:: ty:: subst:: SubstsRef ;
6
7
use rustc_middle:: ty:: util:: { needs_drop_components, AlwaysRequiresDrop } ;
7
8
use rustc_middle:: ty:: { self , Ty , TyCtxt } ;
8
9
use rustc_session:: Limit ;
@@ -12,7 +13,8 @@ type NeedsDropResult<T> = Result<T, AlwaysRequiresDrop>;
12
13
13
14
fn needs_drop_raw < ' tcx > ( tcx : TyCtxt < ' tcx > , query : ty:: ParamEnvAnd < ' tcx , Ty < ' tcx > > ) -> bool {
14
15
let adt_fields =
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 ( ) ) ;
17
+
16
18
// If we don't know a type doesn't need drop, for example if it's a type
17
19
// parameter without a `Copy` bound, then we conservatively return that it
18
20
// needs drop.
@@ -25,8 +27,9 @@ fn has_significant_drop_raw<'tcx>(
25
27
tcx : TyCtxt < ' tcx > ,
26
28
query : ty:: ParamEnvAnd < ' tcx , Ty < ' tcx > > ,
27
29
) -> bool {
28
- let significant_drop_fields =
29
- move |adt_def : & ty:: AdtDef | tcx. adt_significant_drop_tys ( adt_def. did ) . map ( |tys| tys. iter ( ) ) ;
30
+ let significant_drop_fields = move |adt_def : & ty:: AdtDef , _| {
31
+ tcx. adt_significant_drop_tys ( adt_def. did ) . map ( |tys| tys. iter ( ) )
32
+ } ;
30
33
let res = NeedsDropTypes :: new ( tcx, query. param_env , query. value , significant_drop_fields)
31
34
. next ( )
32
35
. is_some ( ) ;
@@ -71,7 +74,7 @@ impl<'tcx, F> NeedsDropTypes<'tcx, F> {
71
74
72
75
impl < ' tcx , F , I > Iterator for NeedsDropTypes < ' tcx , F >
73
76
where
74
- F : Fn ( & ty:: AdtDef ) -> NeedsDropResult < I > ,
77
+ F : Fn ( & ty:: AdtDef , SubstsRef < ' tcx > ) -> NeedsDropResult < I > ,
75
78
I : Iterator < Item = Ty < ' tcx > > ,
76
79
{
77
80
type Item = NeedsDropResult < Ty < ' tcx > > ;
@@ -135,7 +138,7 @@ where
135
138
// `ManuallyDrop`. If it's a struct or enum without a `Drop`
136
139
// impl then check whether the field types need `Drop`.
137
140
ty:: Adt ( adt_def, substs) => {
138
- let tys = match ( self . adt_components ) ( adt_def) {
141
+ let tys = match ( self . adt_components ) ( adt_def, substs ) {
139
142
Err ( e) => return Some ( Err ( e) ) ,
140
143
Ok ( tys) => tys,
141
144
} ;
@@ -168,22 +171,44 @@ where
168
171
}
169
172
}
170
173
174
+ enum DtorType {
175
+ /// Type has a `Drop` but it is considered insignificant.
176
+ /// Check the query `adt_significant_drop_tys` for understanding
177
+ /// "significant" / "insignificant".
178
+ Insignificant ,
179
+
180
+ /// Type has a `Drop` implentation.
181
+ Significant ,
182
+ }
183
+
171
184
// This is a helper function for `adt_drop_tys` and `adt_significant_drop_tys`.
172
185
// Depending on the implentation of `adt_has_dtor`, it is used to check if the
173
186
// ADT has a destructor or if the ADT only has a significant destructor. For
174
187
// understanding significant destructor look at `adt_significant_drop_tys`.
175
- fn adt_drop_tys_helper (
176
- tcx : TyCtxt < ' _ > ,
188
+ fn adt_drop_tys_helper < ' tcx > (
189
+ tcx : TyCtxt < ' tcx > ,
177
190
def_id : DefId ,
178
- adt_has_dtor : impl Fn ( & ty:: AdtDef ) -> bool ,
179
- ) -> Result < & ty:: List < Ty < ' _ > > , AlwaysRequiresDrop > {
180
- let adt_components = move |adt_def : & ty:: AdtDef | {
191
+ adt_has_dtor : impl Fn ( & ty:: AdtDef ) -> Option < DtorType > ,
192
+ ) -> Result < & ty:: List < Ty < ' tcx > > , AlwaysRequiresDrop > {
193
+ let adt_components = move |adt_def : & ty:: AdtDef , substs : SubstsRef < ' tcx > | {
181
194
if adt_def. is_manually_drop ( ) {
182
195
debug ! ( "adt_drop_tys: `{:?}` is manually drop" , adt_def) ;
183
196
return Ok ( Vec :: new ( ) . into_iter ( ) ) ;
184
- } else if adt_has_dtor ( adt_def) {
185
- debug ! ( "adt_drop_tys: `{:?}` implements `Drop`" , adt_def) ;
186
- return Err ( AlwaysRequiresDrop ) ;
197
+ } else if let Some ( dtor_info) = adt_has_dtor ( adt_def) {
198
+ match dtor_info {
199
+ DtorType :: Significant => {
200
+ debug ! ( "adt_drop_tys: `{:?}` implements `Drop`" , adt_def) ;
201
+ return Err ( AlwaysRequiresDrop ) ;
202
+ }
203
+ DtorType :: Insignificant => {
204
+ debug ! ( "adt_drop_tys: `{:?}` drop is insignificant" , adt_def) ;
205
+
206
+ // Since the destructor is insignificant, we just want to make sure all of
207
+ // the passed in type parameters are also insignificant.
208
+ // Eg: Vec<T> dtor is insignificant when T=i32 but significant when T=Mutex.
209
+ return Ok ( substs. types ( ) . collect :: < Vec < Ty < ' _ > > > ( ) . into_iter ( ) ) ;
210
+ }
211
+ }
187
212
} else if adt_def. is_union ( ) {
188
213
debug ! ( "adt_drop_tys: `{:?}` is a union" , adt_def) ;
189
214
return Ok ( Vec :: new ( ) . into_iter ( ) ) ;
@@ -201,7 +226,10 @@ fn adt_drop_tys_helper(
201
226
}
202
227
203
228
fn adt_drop_tys ( tcx : TyCtxt < ' _ > , def_id : DefId ) -> Result < & ty:: List < Ty < ' _ > > , AlwaysRequiresDrop > {
204
- let adt_has_dtor = |adt_def : & ty:: AdtDef | adt_def. destructor ( tcx) . is_some ( ) ;
229
+ // This is for the "needs_drop" query, that considers all `Drop` impls, therefore all dtors are
230
+ // significant.
231
+ let adt_has_dtor =
232
+ |adt_def : & ty:: AdtDef | adt_def. destructor ( tcx) . map ( |_| DtorType :: Significant ) ;
205
233
adt_drop_tys_helper ( tcx, def_id, adt_has_dtor)
206
234
}
207
235
@@ -210,10 +238,22 @@ fn adt_significant_drop_tys(
210
238
def_id : DefId ,
211
239
) -> Result < & ty:: List < Ty < ' _ > > , AlwaysRequiresDrop > {
212
240
let adt_has_dtor = |adt_def : & ty:: AdtDef | {
213
- adt_def
214
- . destructor ( tcx)
215
- . map ( |dtor| !tcx. has_attr ( dtor. did , sym:: rustc_insignificant_dtor) )
216
- . unwrap_or ( false )
241
+ let is_marked_insig = tcx. has_attr ( adt_def. did , sym:: rustc_insignificant_dtor) ;
242
+ if is_marked_insig {
243
+ // In some cases like `std::collections::HashMap` where the struct is a wrapper around
244
+ // a type that is a Drop type, and the wrapped type (eg: `hashbrown::HashMap`) lies
245
+ // outside stdlib, we might choose to still annotate the the wrapper (std HashMap) with
246
+ // `rustc_insignificant_dtor`, even if the type itself doesn't have a `Drop` impl.
247
+ Some ( DtorType :: Insignificant )
248
+ } else if adt_def. destructor ( tcx) . is_some ( ) {
249
+ // There is a Drop impl and the type isn't marked insignificant, therefore Drop must be
250
+ // significant.
251
+ Some ( DtorType :: Significant )
252
+ } else {
253
+ // No destructor found nor the type is annotated with `rustc_insignificant_dtor`, we
254
+ // treat this as the simple case of Drop impl for type.
255
+ None
256
+ }
217
257
} ;
218
258
adt_drop_tys_helper ( tcx, def_id, adt_has_dtor)
219
259
}
0 commit comments