1 // Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
12 use check
::regionck
::RegionCtxt
;
14 use hir
::def_id
::DefId
;
15 use middle
::free_region
::FreeRegionMap
;
16 use rustc
::infer
::{self, InferOk}
;
18 use rustc
::ty
::subst
::{Subst, Substs}
;
19 use rustc
::ty
::{self, AdtKind, Ty, TyCtxt}
;
20 use rustc
::traits
::{self, Reveal}
;
21 use util
::nodemap
::FnvHashSet
;
24 use syntax_pos
::{self, Span}
;
26 /// check_drop_impl confirms that the Drop implementation identfied by
27 /// `drop_impl_did` is not any more specialized than the type it is
28 /// attached to (Issue #8142).
32 /// 1. The self type must be nominal (this is already checked during
35 /// 2. The generic region/type parameters of the impl's self-type must
36 /// all be parameters of the Drop impl itself (i.e. no
37 /// specialization like `impl Drop for Foo<i32>`), and,
39 /// 3. Any bounds on the generic parameters must be reflected in the
40 /// struct/enum definition for the nominal type itself (i.e.
41 /// cannot do `struct S<T>; impl<T:Clone> Drop for S<T> { ... }`).
43 pub fn check_drop_impl(ccx
: &CrateCtxt
, drop_impl_did
: DefId
) -> Result
<(), ()> {
44 let dtor_self_type
= ccx
.tcx
.lookup_item_type(drop_impl_did
).ty
;
45 let dtor_predicates
= ccx
.tcx
.lookup_predicates(drop_impl_did
);
46 match dtor_self_type
.sty
{
47 ty
::TyAdt(adt_def
, self_to_impl_substs
) => {
48 ensure_drop_params_and_item_params_correspond(ccx
,
53 ensure_drop_predicates_are_implied_by_item_defn(ccx
,
60 // Destructors only work on nominal types. This was
61 // already checked by coherence, so we can panic here.
62 let span
= ccx
.tcx
.map
.def_id_span(drop_impl_did
, syntax_pos
::DUMMY_SP
);
64 "should have been rejected by coherence check: {}",
70 fn ensure_drop_params_and_item_params_correspond
<'a
, 'tcx
>(
71 ccx
: &CrateCtxt
<'a
, 'tcx
>,
73 drop_impl_ty
: Ty
<'tcx
>,
78 let drop_impl_node_id
= tcx
.map
.as_local_node_id(drop_impl_did
).unwrap();
79 let self_type_node_id
= tcx
.map
.as_local_node_id(self_type_did
).unwrap();
81 // check that the impl type can be made to match the trait type.
83 let impl_param_env
= ty
::ParameterEnvironment
::for_item(tcx
, self_type_node_id
);
84 tcx
.infer_ctxt(None
, Some(impl_param_env
), Reveal
::NotSpecializable
).enter(|infcx
| {
86 let mut fulfillment_cx
= traits
::FulfillmentContext
::new();
88 let named_type
= tcx
.lookup_item_type(self_type_did
).ty
;
89 let named_type
= named_type
.subst(tcx
, &infcx
.parameter_environment
.free_substs
);
91 let drop_impl_span
= tcx
.map
.def_id_span(drop_impl_did
, syntax_pos
::DUMMY_SP
);
92 let fresh_impl_substs
=
93 infcx
.fresh_substs_for_item(drop_impl_span
, drop_impl_did
);
94 let fresh_impl_self_ty
= drop_impl_ty
.subst(tcx
, fresh_impl_substs
);
96 match infcx
.eq_types(true, infer
::TypeOrigin
::Misc(drop_impl_span
),
97 named_type
, fresh_impl_self_ty
) {
98 Ok(InferOk { obligations, .. }
) => {
99 // FIXME(#32730) propagate obligations
100 assert
!(obligations
.is_empty());
103 let item_span
= tcx
.map
.span(self_type_node_id
);
104 struct_span_err
!(tcx
.sess
, drop_impl_span
, E0366
,
105 "Implementations of Drop cannot be specialized")
106 .span_note(item_span
,
107 "Use same sequence of generic type and region \
108 parameters that is on the struct/enum definition")
114 if let Err(ref errors
) = fulfillment_cx
.select_all_or_error(&infcx
) {
115 // this could be reached when we get lazy normalization
116 infcx
.report_fulfillment_errors(errors
);
120 let free_regions
= FreeRegionMap
::new();
121 infcx
.resolve_regions_and_report_errors(&free_regions
, drop_impl_node_id
);
126 /// Confirms that every predicate imposed by dtor_predicates is
127 /// implied by assuming the predicates attached to self_type_did.
128 fn ensure_drop_predicates_are_implied_by_item_defn
<'a
, 'tcx
>(
129 ccx
: &CrateCtxt
<'a
, 'tcx
>,
130 drop_impl_did
: DefId
,
131 dtor_predicates
: &ty
::GenericPredicates
<'tcx
>,
132 self_type_did
: DefId
,
133 self_to_impl_substs
: &Substs
<'tcx
>)
137 // Here is an example, analogous to that from
138 // `compare_impl_method`.
140 // Consider a struct type:
142 // struct Type<'c, 'b:'c, 'a> {
143 // x: &'a Contents // (contents are irrelevant;
144 // y: &'c Cell<&'b Contents>, // only the bounds matter for our purposes.)
149 // impl<'z, 'y:'z, 'x:'y> Drop for P<'z, 'y, 'x> {
150 // fn drop(&mut self) { self.y.set(self.x); } // (only legal if 'x: 'y)
153 // We start out with self_to_impl_substs, that maps the generic
154 // parameters of Type to that of the Drop impl.
156 // self_to_impl_substs = {'c => 'z, 'b => 'y, 'a => 'x}
158 // Applying this to the predicates (i.e. assumptions) provided by the item
159 // definition yields the instantiated assumptions:
163 // We then check all of the predicates of the Drop impl:
167 // and ensure each is in the list of instantiated
168 // assumptions. Here, `'y:'z` is present, but `'x:'y` is
169 // absent. So we report an error that the Drop impl injected a
170 // predicate that is not present on the struct definition.
174 let self_type_node_id
= tcx
.map
.as_local_node_id(self_type_did
).unwrap();
176 let drop_impl_span
= tcx
.map
.def_id_span(drop_impl_did
, syntax_pos
::DUMMY_SP
);
178 // We can assume the predicates attached to struct/enum definition
180 let generic_assumptions
= tcx
.lookup_predicates(self_type_did
);
182 let assumptions_in_impl_context
= generic_assumptions
.instantiate(tcx
, &self_to_impl_substs
);
183 let assumptions_in_impl_context
= assumptions_in_impl_context
.predicates
;
185 // An earlier version of this code attempted to do this checking
186 // via the traits::fulfill machinery. However, it ran into trouble
187 // since the fulfill machinery merely turns outlives-predicates
188 // 'a:'b and T:'b into region inference constraints. It is simpler
189 // just to look for all the predicates directly.
191 assert_eq
!(dtor_predicates
.parent
, None
);
192 for predicate
in &dtor_predicates
.predicates
{
193 // (We do not need to worry about deep analysis of type
194 // expressions etc because the Drop impls are already forced
195 // to take on a structure that is roughly an alpha-renaming of
196 // the generic parameters of the item definition.)
198 // This path now just checks *all* predicates via the direct
199 // lookup, rather than using fulfill machinery.
201 // However, it may be more efficient in the future to batch
202 // the analysis together via the fulfill , rather than the
203 // repeated `contains` calls.
205 if !assumptions_in_impl_context
.contains(&predicate
) {
206 let item_span
= tcx
.map
.span(self_type_node_id
);
207 struct_span_err
!(tcx
.sess
, drop_impl_span
, E0367
,
208 "The requirement `{}` is added only by the Drop impl.", predicate
)
209 .span_note(item_span
,
210 "The same requirement must be part of \
211 the struct/enum definition")
216 if tcx
.sess
.has_errors() {
222 /// check_safety_of_destructor_if_necessary confirms that the type
223 /// expression `typ` conforms to the "Drop Check Rule" from the Sound
224 /// Generic Drop (RFC 769).
228 /// The simplified (*) Drop Check Rule is the following:
230 /// Let `v` be some value (either temporary or named) and 'a be some
231 /// lifetime (scope). If the type of `v` owns data of type `D`, where
233 /// * (1.) `D` has a lifetime- or type-parametric Drop implementation,
234 /// (where that `Drop` implementation does not opt-out of
235 /// this check via the `unsafe_destructor_blind_to_params`
237 /// * (2.) the structure of `D` can reach a reference of type `&'a _`,
239 /// then 'a must strictly outlive the scope of v.
243 /// This function is meant to by applied to the type for every
244 /// expression in the program.
248 /// (*) The qualifier "simplified" is attached to the above
249 /// definition of the Drop Check Rule, because it is a simplification
250 /// of the original Drop Check rule, which attempted to prove that
251 /// some `Drop` implementations could not possibly access data even if
252 /// it was technically reachable, due to parametricity.
254 /// However, (1.) parametricity on its own turned out to be a
255 /// necessary but insufficient condition, and (2.) future changes to
256 /// the language are expected to make it impossible to ensure that a
257 /// `Drop` implementation is actually parametric with respect to any
258 /// particular type parameter. (In particular, impl specialization is
259 /// expected to break the needed parametricity property beyond
262 /// Therefore we have scaled back Drop-Check to a more conservative
263 /// rule that does not attempt to deduce whether a `Drop`
264 /// implementation could not possible access data of a given lifetime;
265 /// instead Drop-Check now simply assumes that if a destructor has
266 /// access (direct or indirect) to a lifetime parameter, then that
267 /// lifetime must be forced to outlive that destructor's dynamic
268 /// extent. We then provide the `unsafe_destructor_blind_to_params`
269 /// attribute as a way for destructor implementations to opt-out of
270 /// this conservative assumption (and thus assume the obligation of
271 /// ensuring that they do not access data nor invoke methods of
272 /// values that have been previously dropped).
274 pub fn check_safety_of_destructor_if_necessary
<'a
, 'gcx
, 'tcx
>(
275 rcx
: &mut RegionCtxt
<'a
, 'gcx
, 'tcx
>,
278 scope
: region
::CodeExtent
)
280 debug
!("check_safety_of_destructor_if_necessary typ: {:?} scope: {:?}",
283 let parent_scope
= rcx
.tcx
.region_maps
.opt_encl_scope(scope
).unwrap_or_else(|| {
284 span_bug
!(span
, "no enclosing scope found for scope: {:?}", scope
)
287 let result
= iterate_over_potentially_unsafe_regions_in_type(
291 parent_scope
: parent_scope
,
292 breadcrumbs
: FnvHashSet()
299 Err(Error
::Overflow(ref ctxt
, ref detected_on_typ
)) => {
301 let mut err
= struct_span_err
!(tcx
.sess
, span
, E0320
,
302 "overflow while adding drop-check rules for {}", typ
);
304 TypeContext
::Root
=> {
305 // no need for an additional note if the overflow
306 // was somehow on the root.
308 TypeContext
::ADT { def_id, variant, field }
=> {
309 let adt
= tcx
.lookup_adt_def(def_id
);
310 let variant_name
= match adt
.adt_kind() {
311 AdtKind
::Enum
=> format
!("enum {} variant {}",
312 tcx
.item_path_str(def_id
),
314 AdtKind
::Struct
=> format
!("struct {}",
315 tcx
.item_path_str(def_id
)),
316 AdtKind
::Union
=> format
!("union {}",
317 tcx
.item_path_str(def_id
)),
322 "overflowed on {} field {} type: {}",
334 Overflow(TypeContext
, ty
::Ty
<'tcx
>),
337 #[derive(Copy, Clone)]
347 struct DropckContext
<'a
, 'b
: 'a
, 'gcx
: 'b
+'tcx
, 'tcx
: 'b
> {
348 rcx
: &'a
mut RegionCtxt
<'b
, 'gcx
, 'tcx
>,
349 /// types that have already been traversed
350 breadcrumbs
: FnvHashSet
<Ty
<'tcx
>>,
351 /// span for error reporting
353 /// the scope reachable dtorck types must outlive
354 parent_scope
: region
::CodeExtent
357 // `context` is used for reporting overflow errors
358 fn iterate_over_potentially_unsafe_regions_in_type
<'a
, 'b
, 'gcx
, 'tcx
>(
359 cx
: &mut DropckContext
<'a
, 'b
, 'gcx
, 'tcx
>,
360 context
: TypeContext
,
363 -> Result
<(), Error
<'tcx
>>
365 let tcx
= cx
.rcx
.tcx
;
366 // Issue #22443: Watch out for overflow. While we are careful to
367 // handle regular types properly, non-regular ones cause problems.
368 let recursion_limit
= tcx
.sess
.recursion_limit
.get();
369 if depth
/ 4 >= recursion_limit
{
370 // This can get into rather deep recursion, especially in the
371 // presence of things like Vec<T> -> Unique<T> -> PhantomData<T> -> T.
372 // use a higher recursion limit to avoid errors.
373 return Err(Error
::Overflow(context
, ty
))
376 // canoncialize the regions in `ty` before inserting - infinitely many
377 // region variables can refer to the same region.
378 let ty
= cx
.rcx
.resolve_type_and_region_vars_if_possible(&ty
);
380 if !cx
.breadcrumbs
.insert(ty
) {
381 debug
!("iterate_over_potentially_unsafe_regions_in_type \
382 {}ty: {} scope: {:?} - cached",
383 (0..depth
).map(|_
| ' '
).collect
::<String
>(),
384 ty
, cx
.parent_scope
);
385 return Ok(()); // we already visited this type
387 debug
!("iterate_over_potentially_unsafe_regions_in_type \
388 {}ty: {} scope: {:?}",
389 (0..depth
).map(|_
| ' '
).collect
::<String
>(),
390 ty
, cx
.parent_scope
);
392 // If `typ` has a destructor, then we must ensure that all
393 // borrowed data reachable via `typ` must outlive the parent
394 // of `scope`. This is handled below.
396 // However, there is an important special case: for any Drop
397 // impl that is tagged as "blind" to their parameters,
398 // we assume that data borrowed via such type parameters
399 // remains unreachable via that Drop impl.
401 // For example, consider:
404 // #[unsafe_destructor_blind_to_params]
405 // impl<T> Drop for Vec<T> { ... }
408 // which does have to be able to drop instances of `T`, but
409 // otherwise cannot read data from `T`.
411 // Of course, for the type expression passed in for any such
412 // unbounded type parameter `T`, we must resume the recursive
413 // analysis on `T` (since it would be ignored by
414 // type_must_outlive).
415 let dropck_kind
= has_dtor_of_interest(tcx
, ty
);
416 debug
!("iterate_over_potentially_unsafe_regions_in_type \
417 ty: {:?} dropck_kind: {:?}", ty
, dropck_kind
);
419 DropckKind
::NoBorrowedDataAccessedInMyDtor
=> {
420 // The maximally blind attribute.
422 DropckKind
::BorrowedDataMustStrictlyOutliveSelf
=> {
423 cx
.rcx
.type_must_outlive(infer
::SubregionOrigin
::SafeDestructor(cx
.span
),
424 ty
, tcx
.mk_region(ty
::ReScope(cx
.parent_scope
)));
427 DropckKind
::RevisedSelf(revised_ty
) => {
428 cx
.rcx
.type_must_outlive(infer
::SubregionOrigin
::SafeDestructor(cx
.span
),
429 revised_ty
, tcx
.mk_region(ty
::ReScope(cx
.parent_scope
)));
430 // Do not return early from this case; we want
431 // to recursively process the internal structure of Self
432 // (because even though the Drop for Self has been asserted
433 // safe, the types instantiated for the generics of Self
434 // may themselves carry dropck constraints.)
438 debug
!("iterate_over_potentially_unsafe_regions_in_type \
439 {}ty: {} scope: {:?} - checking interior",
440 (0..depth
).map(|_
| ' '
).collect
::<String
>(),
441 ty
, cx
.parent_scope
);
443 // We still need to ensure all referenced data is safe.
445 ty
::TyBool
| ty
::TyChar
| ty
::TyInt(_
) | ty
::TyUint(_
) |
446 ty
::TyFloat(_
) | ty
::TyStr
| ty
::TyNever
=> {
447 // primitive - definitely safe
451 ty
::TyBox(ity
) | ty
::TyArray(ity
, _
) | ty
::TySlice(ity
) => {
452 // single-element containers, behave like their element
453 iterate_over_potentially_unsafe_regions_in_type(
454 cx
, context
, ity
, depth
+1)
457 ty
::TyAdt(def
, substs
) if def
.is_phantom_data() => {
458 // PhantomData<T> - behaves identically to T
459 let ity
= substs
.type_at(0);
460 iterate_over_potentially_unsafe_regions_in_type(
461 cx
, context
, ity
, depth
+1)
464 ty
::TyAdt(def
, substs
) => {
466 for variant
in &def
.variants
{
467 for field
in variant
.fields
.iter() {
468 let fty
= field
.ty(tcx
, substs
);
469 let fty
= cx
.rcx
.fcx
.resolve_type_vars_with_obligations(
470 cx
.rcx
.fcx
.normalize_associated_types_in(cx
.span
, &fty
));
471 iterate_over_potentially_unsafe_regions_in_type(
476 variant
: variant
.name
,
486 ty
::TyClosure(_
, ty
::ClosureSubsts { upvar_tys: tys, .. }
) => {
488 iterate_over_potentially_unsafe_regions_in_type(cx
, context
, ty
, depth
+1)?
493 ty
::TyRawPtr(..) | ty
::TyRef(..) | ty
::TyParam(..) => {
494 // these always come with a witness of liveness (references
495 // explicitly, pointers implicitly, parameters by the
500 ty
::TyFnDef(..) | ty
::TyFnPtr(_
) => {
501 // FIXME(#26656): this type is always destruction-safe, but
502 // it implicitly witnesses Self: Fn, which can be false.
506 ty
::TyInfer(..) | ty
::TyError
=> {
507 tcx
.sess
.delay_span_bug(cx
.span
, "unresolved type in regionck");
511 // these are always dtorck
512 ty
::TyTrait(..) | ty
::TyProjection(_
) | ty
::TyAnon(..) => bug
!(),
516 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
517 enum DropckKind
<'tcx
> {
518 /// The "safe" kind; i.e. conservatively assume any borrow
519 /// accessed by dtor, and therefore such data must strictly
522 /// Equivalent to RevisedTy with no change to the self type.
523 BorrowedDataMustStrictlyOutliveSelf
,
525 /// The nearly completely-unsafe kind.
527 /// Equivalent to RevisedSelf with *all* parameters remapped to ()
529 NoBorrowedDataAccessedInMyDtor
,
531 /// Assume all borrowed data access by dtor occurs as if Self has the
532 /// type carried by this variant. In practice this means that some
533 /// of the type parameters are remapped to `()` (and some lifetime
534 /// parameters remapped to `'static`), because the developer has asserted
535 /// that the destructor will not access their contents.
536 RevisedSelf(Ty
<'tcx
>),
539 /// Returns the classification of what kind of check should be applied
540 /// to `ty`, which may include a revised type where some of the type
541 /// parameters are re-mapped to `()` to reflect the destructor's
542 /// "purity" with respect to their actual contents.
543 fn has_dtor_of_interest
<'a
, 'gcx
, 'tcx
>(tcx
: TyCtxt
<'a
, 'gcx
, 'tcx
>,
545 -> DropckKind
<'tcx
> {
547 ty
::TyAdt(adt_def
, substs
) => {
548 if !adt_def
.is_dtorck(tcx
) {
549 return DropckKind
::NoBorrowedDataAccessedInMyDtor
;
552 // Find the `impl<..> Drop for _` to inspect any
553 // attributes attached to the impl's generics.
554 let dtor_method
= adt_def
.destructor()
555 .expect("dtorck type without destructor impossible");
556 let method
= tcx
.impl_or_trait_item(dtor_method
);
557 let impl_id
: DefId
= method
.container().id();
558 let revised_ty
= revise_self_ty(tcx
, adt_def
, impl_id
, substs
);
559 return DropckKind
::RevisedSelf(revised_ty
);
561 ty
::TyTrait(..) | ty
::TyProjection(..) | ty
::TyAnon(..) => {
562 debug
!("ty: {:?} isn't known, and therefore is a dropck type", ty
);
563 return DropckKind
::BorrowedDataMustStrictlyOutliveSelf
;
566 return DropckKind
::NoBorrowedDataAccessedInMyDtor
;
571 // Constructs new Ty just like the type defined by `adt_def` coupled
572 // with `substs`, except each type and lifetime parameter marked as
573 // `#[may_dangle]` in the Drop impl (identified by `impl_id`) is
574 // respectively mapped to `()` or `'static`.
576 // For example: If the `adt_def` maps to:
578 // enum Foo<'a, X, Y> { ... }
580 // and the `impl_id` maps to:
582 // impl<#[may_dangle] 'a, X, #[may_dangle] Y> Drop for Foo<'a, X, Y> { ... }
584 // then revises input: `Foo<'r,i64,&'r i64>` to: `Foo<'static,i64,()>`
585 fn revise_self_ty
<'a
, 'gcx
, 'tcx
>(tcx
: TyCtxt
<'a
, 'gcx
, 'tcx
>,
586 adt_def
: ty
::AdtDef
<'tcx
>,
588 substs
: &Substs
<'tcx
>)
590 // Get generics for `impl Drop` to query for `#[may_dangle]` attr.
591 let impl_bindings
= tcx
.lookup_generics(impl_id
);
593 // Get Substs attached to Self on `impl Drop`; process in parallel
594 // with `substs`, replacing dangling entries as appropriate.
596 let impl_self_ty
: Ty
<'tcx
> = tcx
.lookup_item_type(impl_id
).ty
;
597 if let ty
::TyAdt(self_adt_def
, self_substs
) = impl_self_ty
.sty
{
598 assert_eq
!(adt_def
, self_adt_def
);
601 bug
!("Self in `impl Drop for _` must be an Adt.");
605 // Walk `substs` + `self_substs`, build new substs appropriate for
606 // `adt_def`; each non-dangling param reuses entry from `substs`.
608 // Note: The manner we map from a right-hand side (i.e. Region or
609 // Ty) for a given `def` to generic parameter associated with that
610 // right-hand side is tightly coupled to `Drop` impl constraints.
612 // E.g. we know such a Ty must be `TyParam`, because a destructor
613 // for `struct Foo<X>` is defined via `impl<Y> Drop for Foo<Y>`,
614 // and never by (for example) `impl<Z> Drop for Foo<Vec<Z>>`.
615 let substs
= Substs
::for_item(
619 let r_orig
= substs
.region_for_def(def
);
620 let impl_self_orig
= self_substs
.region_for_def(def
);
621 let r
= if let ty
::Region
::ReEarlyBound(ref ebr
) = *impl_self_orig
{
622 if impl_bindings
.region_param(ebr
).pure_wrt_drop
{
623 tcx
.mk_region(ty
::ReStatic
)
628 bug
!("substs for an impl must map regions to ReEarlyBound");
630 debug
!("has_dtor_of_interest mapping def {:?} orig {:?} to {:?}",
635 let t_orig
= substs
.type_for_def(def
);
636 let impl_self_orig
= self_substs
.type_for_def(def
);
637 let t
= if let ty
::TypeVariants
::TyParam(ref pt
) = impl_self_orig
.sty
{
638 if impl_bindings
.type_param(pt
).pure_wrt_drop
{
644 bug
!("substs for an impl must map types to TyParam");
646 debug
!("has_dtor_of_interest mapping def {:?} orig {:?} {:?} to {:?} {:?}",
647 def
, t_orig
, t_orig
.sty
, t
, t
.sty
);
651 return tcx
.mk_adt(adt_def
, &substs
);