@@ -217,26 +217,52 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
217
217
///
218
218
/// ----
219
219
///
220
- /// The Drop Check Rule is the following:
220
+ /// The simplified (*) Drop Check Rule is the following:
221
221
///
222
222
/// Let `v` be some value (either temporary or named) and 'a be some
223
223
/// lifetime (scope). If the type of `v` owns data of type `D`, where
224
224
///
225
- /// * (1.) `D` has a lifetime- or type-parametric Drop implementation, and
226
- /// * (2.) the structure of `D` can reach a reference of type `&'a _`, and
227
- /// * (3.) either:
228
- /// * (A.) the Drop impl for `D` instantiates `D` at 'a directly,
229
- /// i.e. `D<'a>`, or,
230
- /// * (B.) the Drop impl for `D` has some type parameter with a
231
- /// trait bound `T` where `T` is a trait that has at least
232
- /// one method,
225
+ /// * (1.) `D` has a lifetime- or type-parametric Drop implementation,
226
+ /// (where that `Drop` implementation does not opt-out of
227
+ /// this check via the `unsafe_destructor_blind_to_params`
228
+ /// attribute), and
229
+ /// * (2.) the structure of `D` can reach a reference of type `&'a _`,
233
230
///
234
231
/// then 'a must strictly outlive the scope of v.
235
232
///
236
233
/// ----
237
234
///
238
235
/// This function is meant to by applied to the type for every
239
236
/// expression in the program.
237
+ ///
238
+ /// ----
239
+ ///
240
+ /// (*) The qualifier "simplified" is attached to the above
241
+ /// definition of the Drop Check Rule, because it is a simplification
242
+ /// of the original Drop Check rule, which attempted to prove that
243
+ /// some `Drop` implementations could not possibly access data even if
244
+ /// it was technically reachable, due to parametricity.
245
+ ///
246
+ /// However, (1.) parametricity on its own turned out to be a
247
+ /// necessary but insufficient condition, and (2.) future changes to
248
+ /// the language are expected to make it impossible to ensure that a
249
+ /// `Drop` implementation is actually parametric with respect to any
250
+ /// particular type parameter. (In particular, impl specialization is
251
+ /// expected to break the needed parametricity property beyond
252
+ /// repair.)
253
+ ///
254
+ /// Therefore we have scaled back Drop-Check to a more conservative
255
+ /// rule that does not attempt to deduce whether a `Drop`
256
+ /// implementation could not possible access data of a given lifetime;
257
+ /// instead Drop-Check now simply assumes that if a destructor has
258
+ /// access (direct or indirect) to a lifetime parameter, then that
259
+ /// lifetime must be forced to outlive that destructor's dynamic
260
+ /// extent. We then provide the `unsafe_destructor_blind_to_params`
261
+ /// attribute as a way for destructor implementations to opt-out of
262
+ /// this conservative assumption (and thus assume the obligation of
263
+ /// ensuring that they do not access data nor invoke methods of
264
+ /// values that have been previously dropped).
265
+ ///
240
266
pub fn check_safety_of_destructor_if_necessary < ' a , ' tcx > ( rcx : & mut Rcx < ' a , ' tcx > ,
241
267
typ : ty:: Ty < ' tcx > ,
242
268
span : Span ,
@@ -356,30 +382,25 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'tcx>(
356
382
// borrowed data reachable via `typ` must outlive the parent
357
383
// of `scope`. This is handled below.
358
384
//
359
- // However, there is an important special case: by
360
- // parametricity, any generic type parameters have *no* trait
361
- // bounds in the Drop impl can not be used in any way (apart
362
- // from being dropped), and thus we can treat data borrowed
363
- // via such type parameters remains unreachable.
385
+ // However, there is an important special case: for any Drop
386
+ // impl that is tagged as "blind" to their parameters,
387
+ // we assume that data borrowed via such type parameters
388
+ // remains unreachable via that Drop impl.
389
+ //
390
+ // For example, consider:
391
+ //
392
+ // ```rust
393
+ // #[unsafe_destructor_blind_to_params]
394
+ // impl<T> Drop for Vec<T> { ... }
395
+ // ```
364
396
//
365
- // For example, consider `impl<T> Drop for Vec<T> { ... }`,
366
397
// which does have to be able to drop instances of `T`, but
367
398
// otherwise cannot read data from `T`.
368
399
//
369
400
// Of course, for the type expression passed in for any such
370
401
// unbounded type parameter `T`, we must resume the recursive
371
402
// analysis on `T` (since it would be ignored by
372
403
// type_must_outlive).
373
- //
374
- // FIXME (pnkfelix): Long term, we could be smart and actually
375
- // feed which generic parameters can be ignored *into* `fn
376
- // type_must_outlive` (or some generalization thereof). But
377
- // for the short term, it probably covers most cases of
378
- // interest to just special case Drop impls where: (1.) there
379
- // are no generic lifetime parameters and (2.) *all* generic
380
- // type parameters are unbounded. If both conditions hold, we
381
- // simply skip the `type_must_outlive` call entirely (but
382
- // resume the recursive checking of the type-substructure).
383
404
if has_dtor_of_interest ( tcx, ty) {
384
405
debug ! ( "iterate_over_potentially_unsafe_regions_in_type \
385
406
{}ty: {} - is a dtorck type!",
0 commit comments