]> git.proxmox.com Git - rustc.git/blame - src/librustc_typeck/check/dropck.rs
Imported Upstream version 1.2.0+dfsg1
[rustc.git] / src / librustc_typeck / check / dropck.rs
CommitLineData
85aaf69f
SL
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.
4//
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.
10
11use check::regionck::{self, Rcx};
12
13use middle::infer;
14use middle::region;
c34b1796 15use middle::subst::{self, Subst};
85aaf69f 16use middle::ty::{self, Ty};
c34b1796
AL
17
18use syntax::ast;
19use syntax::codemap::{self, Span};
20
21/// check_drop_impl confirms that the Drop implementation identfied by
22/// `drop_impl_did` is not any more specialized than the type it is
23/// attached to (Issue #8142).
24///
25/// This means:
26///
27/// 1. The self type must be nominal (this is already checked during
28/// coherence),
29///
30/// 2. The generic region/type parameters of the impl's self-type must
31/// all be parameters of the Drop impl itself (i.e. no
32/// specialization like `impl Drop for Foo<i32>`), and,
33///
34/// 3. Any bounds on the generic parameters must be reflected in the
35/// struct/enum definition for the nominal type itself (i.e.
36/// cannot do `struct S<T>; impl<T:Clone> Drop for S<T> { ... }`).
37///
38pub fn check_drop_impl(tcx: &ty::ctxt, drop_impl_did: ast::DefId) -> Result<(), ()> {
39 let ty::TypeScheme { generics: ref dtor_generics,
62682a34 40 ty: dtor_self_type } = ty::lookup_item_type(tcx, drop_impl_did);
c34b1796
AL
41 let dtor_predicates = ty::lookup_predicates(tcx, drop_impl_did);
42 match dtor_self_type.sty {
62682a34
SL
43 ty::TyEnum(self_type_did, self_to_impl_substs) |
44 ty::TyStruct(self_type_did, self_to_impl_substs) |
45 ty::TyClosure(self_type_did, self_to_impl_substs) => {
c34b1796
AL
46 try!(ensure_drop_params_and_item_params_correspond(tcx,
47 drop_impl_did,
48 dtor_generics,
62682a34 49 &dtor_self_type,
c34b1796
AL
50 self_type_did));
51
52 ensure_drop_predicates_are_implied_by_item_defn(tcx,
53 drop_impl_did,
54 &dtor_predicates,
55 self_type_did,
56 self_to_impl_substs)
57 }
58 _ => {
59 // Destructors only work on nominal types. This was
60 // already checked by coherence, so we can panic here.
61 let span = tcx.map.def_id_span(drop_impl_did, codemap::DUMMY_SP);
62 tcx.sess.span_bug(
63 span, &format!("should have been rejected by coherence check: {}",
62682a34 64 dtor_self_type));
c34b1796
AL
65 }
66 }
67}
68
69fn ensure_drop_params_and_item_params_correspond<'tcx>(
70 tcx: &ty::ctxt<'tcx>,
71 drop_impl_did: ast::DefId,
72 drop_impl_generics: &ty::Generics<'tcx>,
73 drop_impl_ty: &ty::Ty<'tcx>,
74 self_type_did: ast::DefId) -> Result<(), ()>
75{
76 // New strategy based on review suggestion from nikomatsakis.
77 //
78 // (In the text and code below, "named" denotes "struct/enum", and
79 // "generic params" denotes "type and region params")
80 //
81 // 1. Create fresh skolemized type/region "constants" for each of
82 // the named type's generic params. Instantiate the named type
83 // with the fresh constants, yielding `named_skolem`.
84 //
85 // 2. Create unification variables for each of the Drop impl's
86 // generic params. Instantiate the impl's Self's type with the
87 // unification-vars, yielding `drop_unifier`.
88 //
89 // 3. Attempt to unify Self_unif with Type_skolem. If unification
90 // succeeds, continue (i.e. with the predicate checks).
91
92 let ty::TypeScheme { generics: ref named_type_generics,
93 ty: named_type } =
94 ty::lookup_item_type(tcx, self_type_did);
95
96 let infcx = infer::new_infer_ctxt(tcx);
97 infcx.commit_if_ok(|snapshot| {
98 let (named_type_to_skolem, skol_map) =
99 infcx.construct_skolemized_subst(named_type_generics, snapshot);
100 let named_type_skolem = named_type.subst(tcx, &named_type_to_skolem);
101
102 let drop_impl_span = tcx.map.def_id_span(drop_impl_did, codemap::DUMMY_SP);
103 let drop_to_unifier =
104 infcx.fresh_substs_for_generics(drop_impl_span, drop_impl_generics);
105 let drop_unifier = drop_impl_ty.subst(tcx, &drop_to_unifier);
106
107 if let Ok(()) = infer::mk_eqty(&infcx, true, infer::TypeOrigin::Misc(drop_impl_span),
108 named_type_skolem, drop_unifier) {
109 // Even if we did manage to equate the types, the process
110 // may have just gathered unsolvable region constraints
111 // like `R == 'static` (represented as a pair of subregion
112 // constraints) for some skolemization constant R.
113 //
114 // However, the leak_check method allows us to confirm
115 // that no skolemized regions escaped (i.e. were related
116 // to other regions in the constraint graph).
117 if let Ok(()) = infcx.leak_check(&skol_map, snapshot) {
118 return Ok(())
119 }
120 }
121
122 span_err!(tcx.sess, drop_impl_span, E0366,
123 "Implementations of Drop cannot be specialized");
124 let item_span = tcx.map.span(self_type_did.node);
125 tcx.sess.span_note(item_span,
126 "Use same sequence of generic type and region \
127 parameters that is on the struct/enum definition");
128 return Err(());
129 })
130}
131
132/// Confirms that every predicate imposed by dtor_predicates is
133/// implied by assuming the predicates attached to self_type_did.
134fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
135 tcx: &ty::ctxt<'tcx>,
136 drop_impl_did: ast::DefId,
137 dtor_predicates: &ty::GenericPredicates<'tcx>,
138 self_type_did: ast::DefId,
139 self_to_impl_substs: &subst::Substs<'tcx>) -> Result<(), ()> {
140
141 // Here is an example, analogous to that from
142 // `compare_impl_method`.
143 //
144 // Consider a struct type:
145 //
146 // struct Type<'c, 'b:'c, 'a> {
147 // x: &'a Contents // (contents are irrelevant;
148 // y: &'c Cell<&'b Contents>, // only the bounds matter for our purposes.)
149 // }
150 //
151 // and a Drop impl:
152 //
153 // impl<'z, 'y:'z, 'x:'y> Drop for P<'z, 'y, 'x> {
154 // fn drop(&mut self) { self.y.set(self.x); } // (only legal if 'x: 'y)
155 // }
156 //
157 // We start out with self_to_impl_substs, that maps the generic
158 // parameters of Type to that of the Drop impl.
159 //
160 // self_to_impl_substs = {'c => 'z, 'b => 'y, 'a => 'x}
161 //
162 // Applying this to the predicates (i.e. assumptions) provided by the item
163 // definition yields the instantiated assumptions:
164 //
165 // ['y : 'z]
166 //
167 // We then check all of the predicates of the Drop impl:
168 //
169 // ['y:'z, 'x:'y]
170 //
171 // and ensure each is in the list of instantiated
172 // assumptions. Here, `'y:'z` is present, but `'x:'y` is
173 // absent. So we report an error that the Drop impl injected a
174 // predicate that is not present on the struct definition.
175
176 assert_eq!(self_type_did.krate, ast::LOCAL_CRATE);
177
178 let drop_impl_span = tcx.map.def_id_span(drop_impl_did, codemap::DUMMY_SP);
179
180 // We can assume the predicates attached to struct/enum definition
181 // hold.
182 let generic_assumptions = ty::lookup_predicates(tcx, self_type_did);
183
184 let assumptions_in_impl_context = generic_assumptions.instantiate(tcx, &self_to_impl_substs);
185 assert!(assumptions_in_impl_context.predicates.is_empty_in(subst::SelfSpace));
186 assert!(assumptions_in_impl_context.predicates.is_empty_in(subst::FnSpace));
187 let assumptions_in_impl_context =
188 assumptions_in_impl_context.predicates.get_slice(subst::TypeSpace);
189
190 // An earlier version of this code attempted to do this checking
191 // via the traits::fulfill machinery. However, it ran into trouble
192 // since the fulfill machinery merely turns outlives-predicates
193 // 'a:'b and T:'b into region inference constraints. It is simpler
194 // just to look for all the predicates directly.
195
196 assert!(dtor_predicates.predicates.is_empty_in(subst::SelfSpace));
197 assert!(dtor_predicates.predicates.is_empty_in(subst::FnSpace));
198 let predicates = dtor_predicates.predicates.get_slice(subst::TypeSpace);
199 for predicate in predicates {
200 // (We do not need to worry about deep analysis of type
201 // expressions etc because the Drop impls are already forced
202 // to take on a structure that is roughly a alpha-renaming of
203 // the generic parameters of the item definition.)
204
205 // This path now just checks *all* predicates via the direct
206 // lookup, rather than using fulfill machinery.
207 //
208 // However, it may be more efficient in the future to batch
209 // the analysis together via the fulfill , rather than the
210 // repeated `contains` calls.
211
212 if !assumptions_in_impl_context.contains(&predicate) {
213 let item_span = tcx.map.span(self_type_did.node);
c34b1796 214 span_err!(tcx.sess, drop_impl_span, E0367,
62682a34 215 "The requirement `{}` is added only by the Drop impl.", predicate);
c34b1796
AL
216 tcx.sess.span_note(item_span,
217 "The same requirement must be part of \
218 the struct/enum definition");
219 }
220 }
85aaf69f 221
c34b1796
AL
222 if tcx.sess.has_errors() {
223 return Err(());
224 }
225 Ok(())
226}
85aaf69f 227
c34b1796
AL
228/// check_safety_of_destructor_if_necessary confirms that the type
229/// expression `typ` conforms to the "Drop Check Rule" from the Sound
230/// Generic Drop (RFC 769).
231///
232/// ----
233///
234/// The Drop Check Rule is the following:
235///
236/// Let `v` be some value (either temporary or named) and 'a be some
237/// lifetime (scope). If the type of `v` owns data of type `D`, where
238///
62682a34
SL
239/// * (1.) `D` has a lifetime- or type-parametric Drop implementation, and
240/// * (2.) the structure of `D` can reach a reference of type `&'a _`, and
241/// * (3.) either:
242/// * (A.) the Drop impl for `D` instantiates `D` at 'a directly,
c34b1796 243/// i.e. `D<'a>`, or,
62682a34 244/// * (B.) the Drop impl for `D` has some type parameter with a
c34b1796
AL
245/// trait bound `T` where `T` is a trait that has at least
246/// one method,
247///
248/// then 'a must strictly outlive the scope of v.
249///
250/// ----
251///
252/// This function is meant to by applied to the type for every
253/// expression in the program.
85aaf69f
SL
254pub fn check_safety_of_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>,
255 typ: ty::Ty<'tcx>,
256 span: Span,
257 scope: region::CodeExtent) {
62682a34
SL
258 debug!("check_safety_of_destructor_if_necessary typ: {:?} scope: {:?}",
259 typ, scope);
85aaf69f
SL
260
261 // types that have been traversed so far by `traverse_type_if_unseen`
262 let mut breadcrumbs: Vec<Ty<'tcx>> = Vec::new();
263
c34b1796 264 let result = iterate_over_potentially_unsafe_regions_in_type(
85aaf69f
SL
265 rcx,
266 &mut breadcrumbs,
c34b1796 267 TypeContext::Root,
85aaf69f
SL
268 typ,
269 span,
270 scope,
c34b1796 271 0,
85aaf69f 272 0);
c34b1796
AL
273 match result {
274 Ok(()) => {}
275 Err(Error::Overflow(ref ctxt, ref detected_on_typ)) => {
276 let tcx = rcx.tcx();
277 span_err!(tcx.sess, span, E0320,
62682a34 278 "overflow while adding drop-check rules for {}", typ);
c34b1796
AL
279 match *ctxt {
280 TypeContext::Root => {
281 // no need for an additional note if the overflow
282 // was somehow on the root.
283 }
284 TypeContext::EnumVariant { def_id, variant, arg_index } => {
285 // FIXME (pnkfelix): eventually lookup arg_name
286 // for the given index on struct variants.
287 span_note!(
288 rcx.tcx().sess,
289 span,
290 "overflowed on enum {} variant {} argument {} type: {}",
291 ty::item_path_str(tcx, def_id),
292 variant,
293 arg_index,
62682a34 294 detected_on_typ);
c34b1796
AL
295 }
296 TypeContext::Struct { def_id, field } => {
297 span_note!(
298 rcx.tcx().sess,
299 span,
300 "overflowed on struct {} field {} type: {}",
301 ty::item_path_str(tcx, def_id),
302 field,
62682a34 303 detected_on_typ);
c34b1796
AL
304 }
305 }
306 }
307 }
308}
309
310enum Error<'tcx> {
311 Overflow(TypeContext, ty::Ty<'tcx>),
85aaf69f
SL
312}
313
c34b1796
AL
314enum TypeContext {
315 Root,
316 EnumVariant {
317 def_id: ast::DefId,
318 variant: ast::Name,
319 arg_index: usize,
320 },
321 Struct {
322 def_id: ast::DefId,
323 field: ast::Name,
324 }
325}
326
327// The `depth` counts the number of calls to this function;
328// the `xref_depth` counts the subset of such calls that go
329// across a `Box<T>` or `PhantomData<T>`.
85aaf69f
SL
330fn iterate_over_potentially_unsafe_regions_in_type<'a, 'tcx>(
331 rcx: &mut Rcx<'a, 'tcx>,
332 breadcrumbs: &mut Vec<Ty<'tcx>>,
c34b1796 333 context: TypeContext,
85aaf69f
SL
334 ty_root: ty::Ty<'tcx>,
335 span: Span,
336 scope: region::CodeExtent,
c34b1796
AL
337 depth: usize,
338 xref_depth: usize) -> Result<(), Error<'tcx>>
85aaf69f 339{
c34b1796
AL
340 // Issue #22443: Watch out for overflow. While we are careful to
341 // handle regular types properly, non-regular ones cause problems.
342 let recursion_limit = rcx.tcx().sess.recursion_limit.get();
343 if xref_depth >= recursion_limit {
344 return Err(Error::Overflow(context, ty_root))
345 }
346
347 let origin = || infer::SubregionOrigin::SafeDestructor(span);
85aaf69f
SL
348 let mut walker = ty_root.walk();
349 let opt_phantom_data_def_id = rcx.tcx().lang_items.phantom_data();
350
351 let destructor_for_type = rcx.tcx().destructor_for_type.borrow();
352
c34b1796
AL
353 let xref_depth_orig = xref_depth;
354
85aaf69f
SL
355 while let Some(typ) = walker.next() {
356 // Avoid recursing forever.
357 if breadcrumbs.contains(&typ) {
358 continue;
359 }
360 breadcrumbs.push(typ);
361
362 // If we encounter `PhantomData<T>`, then we should replace it
363 // with `T`, the type it represents as owned by the
364 // surrounding context, before doing further analysis.
c34b1796 365 let (typ, xref_depth) = match typ.sty {
62682a34 366 ty::TyStruct(struct_did, substs) => {
c34b1796
AL
367 if opt_phantom_data_def_id == Some(struct_did) {
368 let item_type = ty::lookup_item_type(rcx.tcx(), struct_did);
369 let tp_def = item_type.generics.types
370 .opt_get(subst::TypeSpace, 0).unwrap();
371 let new_typ = substs.type_for_def(tp_def);
62682a34
SL
372 debug!("replacing phantom {:?} with {:?}",
373 typ, new_typ);
c34b1796
AL
374 (new_typ, xref_depth_orig + 1)
375 } else {
376 (typ, xref_depth_orig)
377 }
378 }
379
62682a34 380 // Note: When TyBox is removed from compiler, the
c34b1796
AL
381 // definition of `Box<T>` must carry a PhantomData that
382 // puts us into the previous case.
62682a34
SL
383 ty::TyBox(new_typ) => {
384 debug!("replacing TyBox {:?} with {:?}",
385 typ, new_typ);
c34b1796
AL
386 (new_typ, xref_depth_orig + 1)
387 }
388
389 _ => {
390 (typ, xref_depth_orig)
85aaf69f 391 }
85aaf69f
SL
392 };
393
bd371182 394 let dtor_kind = match typ.sty {
62682a34
SL
395 ty::TyEnum(def_id, _) |
396 ty::TyStruct(def_id, _) => {
bd371182
AL
397 match destructor_for_type.get(&def_id) {
398 Some(def_id) => DtorKind::KnownDropMethod(*def_id),
399 None => DtorKind::PureRecur,
400 }
401 }
62682a34 402 ty::TyTrait(ref ty_trait) => {
bd371182
AL
403 DtorKind::Unknown(ty_trait.bounds.clone())
404 }
405 _ => DtorKind::PureRecur,
85aaf69f
SL
406 };
407
85aaf69f 408 debug!("iterate_over_potentially_unsafe_regions_in_type \
bd371182 409 {}typ: {} scope: {:?} xref: {}",
85aaf69f 410 (0..depth).map(|_| ' ').collect::<String>(),
62682a34 411 typ, scope, xref_depth);
85aaf69f
SL
412
413 // If `typ` has a destructor, then we must ensure that all
414 // borrowed data reachable via `typ` must outlive the parent
415 // of `scope`. This is handled below.
416 //
417 // However, there is an important special case: by
418 // parametricity, any generic type parameters have *no* trait
419 // bounds in the Drop impl can not be used in any way (apart
420 // from being dropped), and thus we can treat data borrowed
421 // via such type parameters remains unreachable.
422 //
423 // For example, consider `impl<T> Drop for Vec<T> { ... }`,
424 // which does have to be able to drop instances of `T`, but
425 // otherwise cannot read data from `T`.
426 //
427 // Of course, for the type expression passed in for any such
428 // unbounded type parameter `T`, we must resume the recursive
429 // analysis on `T` (since it would be ignored by
430 // type_must_outlive).
431 //
432 // FIXME (pnkfelix): Long term, we could be smart and actually
433 // feed which generic parameters can be ignored *into* `fn
434 // type_must_outlive` (or some generalization thereof). But
435 // for the short term, it probably covers most cases of
436 // interest to just special case Drop impls where: (1.) there
437 // are no generic lifetime parameters and (2.) *all* generic
438 // type parameters are unbounded. If both conditions hold, we
439 // simply skip the `type_must_outlive` call entirely (but
440 // resume the recursive checking of the type-substructure).
441
bd371182 442 if has_dtor_of_interest(rcx.tcx(), dtor_kind, typ, span) {
85aaf69f
SL
443 // If `typ` has a destructor, then we must ensure that all
444 // borrowed data reachable via `typ` must outlive the
445 // parent of `scope`. (It does not suffice for it to
446 // outlive `scope` because that could imply that the
447 // borrowed data is torn down in between the end of
448 // `scope` and when the destructor itself actually runs.)
449
450 let parent_region =
451 match rcx.tcx().region_maps.opt_encl_scope(scope) {
452 Some(parent_scope) => ty::ReScope(parent_scope),
453 None => rcx.tcx().sess.span_bug(
c34b1796
AL
454 span, &format!("no enclosing scope found for scope: {:?}",
455 scope)),
85aaf69f
SL
456 };
457
458 regionck::type_must_outlive(rcx, origin(), typ, parent_region);
459
460 } else {
461 // Okay, `typ` itself is itself not reachable by a
462 // destructor; but it may contain substructure that has a
463 // destructor.
464
465 match typ.sty {
62682a34
SL
466 ty::TyStruct(struct_did, substs) => {
467 debug!("typ: {:?} is struct; traverse structure and not type-expression",
468 typ);
85aaf69f
SL
469 // Don't recurse; we extract type's substructure,
470 // so do not process subparts of type expression.
471 walker.skip_current_subtree();
472
473 let fields =
474 ty::lookup_struct_fields(rcx.tcx(), struct_did);
62682a34 475 for field in &fields {
85aaf69f
SL
476 let field_type =
477 ty::lookup_field_type(rcx.tcx(),
478 struct_did,
479 field.id,
480 substs);
c34b1796 481 try!(iterate_over_potentially_unsafe_regions_in_type(
85aaf69f
SL
482 rcx,
483 breadcrumbs,
c34b1796
AL
484 TypeContext::Struct {
485 def_id: struct_did,
486 field: field.name,
487 },
85aaf69f
SL
488 field_type,
489 span,
490 scope,
c34b1796
AL
491 depth+1,
492 xref_depth))
85aaf69f
SL
493 }
494 }
495
62682a34
SL
496 ty::TyEnum(enum_did, substs) => {
497 debug!("typ: {:?} is enum; traverse structure and not type-expression",
498 typ);
85aaf69f
SL
499 // Don't recurse; we extract type's substructure,
500 // so do not process subparts of type expression.
501 walker.skip_current_subtree();
502
503 let all_variant_info =
504 ty::substd_enum_variants(rcx.tcx(),
505 enum_did,
506 substs);
62682a34 507 for variant_info in &all_variant_info {
c34b1796
AL
508 for (i, arg_type) in variant_info.args.iter().enumerate() {
509 try!(iterate_over_potentially_unsafe_regions_in_type(
85aaf69f
SL
510 rcx,
511 breadcrumbs,
c34b1796
AL
512 TypeContext::EnumVariant {
513 def_id: enum_did,
514 variant: variant_info.name,
515 arg_index: i,
516 },
517 *arg_type,
85aaf69f
SL
518 span,
519 scope,
c34b1796
AL
520 depth+1,
521 xref_depth));
85aaf69f
SL
522 }
523 }
524 }
525
62682a34 526 ty::TyRef(..) | ty::TyRawPtr(_) | ty::TyBareFn(..) => {
85aaf69f 527 // Don't recurse, since references, pointers,
bd371182 528 // and bare functions don't own instances
85aaf69f
SL
529 // of the types appearing within them.
530 walker.skip_current_subtree();
531 }
532 _ => {}
533 };
534
535 // You might be tempted to pop breadcrumbs here after
536 // processing type's internals above, but then you hit
537 // exponential time blowup e.g. on
538 // compile-fail/huge-struct.rs. Instead, we do not remove
539 // anything from the breadcrumbs vector during any particular
540 // traversal, and instead clear it after the whole traversal
541 // is done.
542 }
543 }
c34b1796
AL
544
545 return Ok(());
85aaf69f 546}
bd371182
AL
547
548enum DtorKind<'tcx> {
549 // Type has an associated drop method with this def id
550 KnownDropMethod(ast::DefId),
551
552 // Type has no destructor (or its dtor is known to be pure
553 // with respect to lifetimes), though its *substructure*
554 // may carry a destructor.
555 PureRecur,
556
557 // Type may have impure destructor that is unknown;
558 // e.g. `Box<Trait+'a>`
559 Unknown(ty::ExistentialBounds<'tcx>),
560}
561
562fn has_dtor_of_interest<'tcx>(tcx: &ty::ctxt<'tcx>,
563 dtor_kind: DtorKind,
564 typ: ty::Ty<'tcx>,
565 span: Span) -> bool {
566 let has_dtor_of_interest: bool;
567
568 match dtor_kind {
569 DtorKind::PureRecur => {
d9579d0f 570 has_dtor_of_interest = false;
62682a34
SL
571 debug!("typ: {:?} has no dtor, and thus is uninteresting",
572 typ);
bd371182
AL
573 }
574 DtorKind::Unknown(bounds) => {
575 match bounds.region_bound {
576 ty::ReStatic => {
62682a34
SL
577 debug!("trait: {:?} has 'static bound, and thus is uninteresting",
578 typ);
bd371182
AL
579 has_dtor_of_interest = false;
580 }
581 ty::ReEmpty => {
62682a34
SL
582 debug!("trait: {:?} has empty region bound, and thus is uninteresting",
583 typ);
bd371182
AL
584 has_dtor_of_interest = false;
585 }
586 r => {
62682a34
SL
587 debug!("trait: {:?} has non-static bound: {:?}; assumed interesting",
588 typ, r);
bd371182
AL
589 has_dtor_of_interest = true;
590 }
591 }
592 }
593 DtorKind::KnownDropMethod(dtor_method_did) => {
594 let impl_did = ty::impl_of_method(tcx, dtor_method_did)
595 .unwrap_or_else(|| {
596 tcx.sess.span_bug(
597 span, "no Drop impl found for drop method")
598 });
599
600 let dtor_typescheme = ty::lookup_item_type(tcx, impl_did);
601 let dtor_generics = dtor_typescheme.generics;
d9579d0f
AL
602
603 let mut has_pred_of_interest = false;
604
605 let mut seen_items = Vec::new();
606 let mut items_to_inspect = vec![impl_did];
607 'items: while let Some(item_def_id) = items_to_inspect.pop() {
608 if seen_items.contains(&item_def_id) {
609 continue;
610 }
611
612 for pred in ty::lookup_predicates(tcx, item_def_id).predicates {
613 let result = match pred {
614 ty::Predicate::Equate(..) |
615 ty::Predicate::RegionOutlives(..) |
616 ty::Predicate::TypeOutlives(..) |
617 ty::Predicate::Projection(..) => {
618 // For now, assume all these where-clauses
619 // may give drop implementation capabilty
620 // to access borrowed data.
621 true
bd371182 622 }
bd371182 623
d9579d0f
AL
624 ty::Predicate::Trait(ty::Binder(ref t_pred)) => {
625 let def_id = t_pred.trait_ref.def_id;
626 if ty::trait_items(tcx, def_id).len() != 0 {
627 // If trait has items, assume it adds
628 // capability to access borrowed data.
629 true
630 } else {
631 // Trait without items is itself
632 // uninteresting from POV of dropck.
633 //
634 // However, may have parent w/ items;
635 // so schedule checking of predicates,
636 items_to_inspect.push(def_id);
637 // and say "no capability found" for now.
638 false
639 }
640 }
641 };
642
643 if result {
644 has_pred_of_interest = true;
62682a34
SL
645 debug!("typ: {:?} has interesting dtor due to generic preds, e.g. {:?}",
646 typ, pred);
d9579d0f
AL
647 break 'items;
648 }
bd371182
AL
649 }
650
d9579d0f
AL
651 seen_items.push(item_def_id);
652 }
bd371182
AL
653
654 // In `impl<'a> Drop ...`, we automatically assume
655 // `'a` is meaningful and thus represents a bound
656 // through which we could reach borrowed data.
657 //
658 // FIXME (pnkfelix): In the future it would be good to
659 // extend the language to allow the user to express,
660 // in the impl signature, that a lifetime is not
661 // actually used (something like `where 'a: ?Live`).
662 let has_region_param_of_interest =
663 dtor_generics.has_region_params(subst::TypeSpace);
664
665 has_dtor_of_interest =
666 has_region_param_of_interest ||
667 has_pred_of_interest;
668
669 if has_dtor_of_interest {
62682a34 670 debug!("typ: {:?} has interesting dtor, due to \
bd371182 671 region params: {} or pred: {}",
62682a34 672 typ,
bd371182
AL
673 has_region_param_of_interest,
674 has_pred_of_interest);
675 } else {
62682a34
SL
676 debug!("typ: {:?} has dtor, but it is uninteresting",
677 typ);
bd371182
AL
678 }
679 }
680 }
681
682 return has_dtor_of_interest;
683}