@@ -217,26 +217,52 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
217217///
218218/// ----
219219///
220- /// The Drop Check Rule is the following:
220+ /// The simplified (*) Drop Check Rule is the following:
221221///
222222/// Let `v` be some value (either temporary or named) and 'a be some
223223/// lifetime (scope). If the type of `v` owns data of type `D`, where
224224///
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 _`,
233230///
234231/// then 'a must strictly outlive the scope of v.
235232///
236233/// ----
237234///
238235/// This function is meant to by applied to the type for every
239236/// 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+ ///
240266pub fn check_safety_of_destructor_if_necessary < ' a , ' tcx > ( rcx : & mut Rcx < ' a , ' tcx > ,
241267 typ : ty:: Ty < ' tcx > ,
242268 span : Span ,
@@ -356,30 +382,25 @@ fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'tcx>(
356382 // borrowed data reachable via `typ` must outlive the parent
357383 // of `scope`. This is handled below.
358384 //
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+ // ```
364396 //
365- // For example, consider `impl<T> Drop for Vec<T> { ... }`,
366397 // which does have to be able to drop instances of `T`, but
367398 // otherwise cannot read data from `T`.
368399 //
369400 // Of course, for the type expression passed in for any such
370401 // unbounded type parameter `T`, we must resume the recursive
371402 // analysis on `T` (since it would be ignored by
372403 // 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).
383404 if has_dtor_of_interest ( tcx, ty) {
384405 debug ! ( "iterate_over_potentially_unsafe_regions_in_type \
385406 {}ty: {} - is a dtorck type!",
0 commit comments