]> git.proxmox.com Git - rustc.git/blame - src/librustc_typeck/check/dropck.rs
Imported Upstream version 1.3.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};
c1a9b12d 17use util::nodemap::FnvHashSet;
c34b1796
AL
18
19use syntax::ast;
20use syntax::codemap::{self, Span};
21
22/// check_drop_impl confirms that the Drop implementation identfied by
23/// `drop_impl_did` is not any more specialized than the type it is
24/// attached to (Issue #8142).
25///
26/// This means:
27///
28/// 1. The self type must be nominal (this is already checked during
29/// coherence),
30///
31/// 2. The generic region/type parameters of the impl's self-type must
32/// all be parameters of the Drop impl itself (i.e. no
33/// specialization like `impl Drop for Foo<i32>`), and,
34///
35/// 3. Any bounds on the generic parameters must be reflected in the
36/// struct/enum definition for the nominal type itself (i.e.
37/// cannot do `struct S<T>; impl<T:Clone> Drop for S<T> { ... }`).
38///
39pub fn check_drop_impl(tcx: &ty::ctxt, drop_impl_did: ast::DefId) -> Result<(), ()> {
40 let ty::TypeScheme { generics: ref dtor_generics,
c1a9b12d
SL
41 ty: dtor_self_type } = tcx.lookup_item_type(drop_impl_did);
42 let dtor_predicates = tcx.lookup_predicates(drop_impl_did);
c34b1796 43 match dtor_self_type.sty {
62682a34 44 ty::TyEnum(self_type_did, self_to_impl_substs) |
c1a9b12d 45 ty::TyStruct(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 } =
c1a9b12d
SL
94 tcx.lookup_item_type(self_type_did);
95
96 let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, false);
c34b1796 97
c34b1796
AL
98 infcx.commit_if_ok(|snapshot| {
99 let (named_type_to_skolem, skol_map) =
100 infcx.construct_skolemized_subst(named_type_generics, snapshot);
101 let named_type_skolem = named_type.subst(tcx, &named_type_to_skolem);
102
103 let drop_impl_span = tcx.map.def_id_span(drop_impl_did, codemap::DUMMY_SP);
104 let drop_to_unifier =
105 infcx.fresh_substs_for_generics(drop_impl_span, drop_impl_generics);
106 let drop_unifier = drop_impl_ty.subst(tcx, &drop_to_unifier);
107
108 if let Ok(()) = infer::mk_eqty(&infcx, true, infer::TypeOrigin::Misc(drop_impl_span),
109 named_type_skolem, drop_unifier) {
110 // Even if we did manage to equate the types, the process
111 // may have just gathered unsolvable region constraints
112 // like `R == 'static` (represented as a pair of subregion
113 // constraints) for some skolemization constant R.
114 //
115 // However, the leak_check method allows us to confirm
116 // that no skolemized regions escaped (i.e. were related
117 // to other regions in the constraint graph).
118 if let Ok(()) = infcx.leak_check(&skol_map, snapshot) {
119 return Ok(())
120 }
121 }
122
123 span_err!(tcx.sess, drop_impl_span, E0366,
124 "Implementations of Drop cannot be specialized");
125 let item_span = tcx.map.span(self_type_did.node);
126 tcx.sess.span_note(item_span,
127 "Use same sequence of generic type and region \
128 parameters that is on the struct/enum definition");
129 return Err(());
130 })
131}
132
133/// Confirms that every predicate imposed by dtor_predicates is
134/// implied by assuming the predicates attached to self_type_did.
135fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
136 tcx: &ty::ctxt<'tcx>,
137 drop_impl_did: ast::DefId,
138 dtor_predicates: &ty::GenericPredicates<'tcx>,
139 self_type_did: ast::DefId,
140 self_to_impl_substs: &subst::Substs<'tcx>) -> Result<(), ()> {
141
142 // Here is an example, analogous to that from
143 // `compare_impl_method`.
144 //
145 // Consider a struct type:
146 //
147 // struct Type<'c, 'b:'c, 'a> {
148 // x: &'a Contents // (contents are irrelevant;
149 // y: &'c Cell<&'b Contents>, // only the bounds matter for our purposes.)
150 // }
151 //
152 // and a Drop impl:
153 //
154 // impl<'z, 'y:'z, 'x:'y> Drop for P<'z, 'y, 'x> {
155 // fn drop(&mut self) { self.y.set(self.x); } // (only legal if 'x: 'y)
156 // }
157 //
158 // We start out with self_to_impl_substs, that maps the generic
159 // parameters of Type to that of the Drop impl.
160 //
161 // self_to_impl_substs = {'c => 'z, 'b => 'y, 'a => 'x}
162 //
163 // Applying this to the predicates (i.e. assumptions) provided by the item
164 // definition yields the instantiated assumptions:
165 //
166 // ['y : 'z]
167 //
168 // We then check all of the predicates of the Drop impl:
169 //
170 // ['y:'z, 'x:'y]
171 //
172 // and ensure each is in the list of instantiated
173 // assumptions. Here, `'y:'z` is present, but `'x:'y` is
174 // absent. So we report an error that the Drop impl injected a
175 // predicate that is not present on the struct definition.
176
177 assert_eq!(self_type_did.krate, ast::LOCAL_CRATE);
178
179 let drop_impl_span = tcx.map.def_id_span(drop_impl_did, codemap::DUMMY_SP);
180
181 // We can assume the predicates attached to struct/enum definition
182 // hold.
c1a9b12d 183 let generic_assumptions = tcx.lookup_predicates(self_type_did);
c34b1796
AL
184
185 let assumptions_in_impl_context = generic_assumptions.instantiate(tcx, &self_to_impl_substs);
186 assert!(assumptions_in_impl_context.predicates.is_empty_in(subst::SelfSpace));
187 assert!(assumptions_in_impl_context.predicates.is_empty_in(subst::FnSpace));
188 let assumptions_in_impl_context =
189 assumptions_in_impl_context.predicates.get_slice(subst::TypeSpace);
190
191 // An earlier version of this code attempted to do this checking
192 // via the traits::fulfill machinery. However, it ran into trouble
193 // since the fulfill machinery merely turns outlives-predicates
194 // 'a:'b and T:'b into region inference constraints. It is simpler
195 // just to look for all the predicates directly.
196
197 assert!(dtor_predicates.predicates.is_empty_in(subst::SelfSpace));
198 assert!(dtor_predicates.predicates.is_empty_in(subst::FnSpace));
199 let predicates = dtor_predicates.predicates.get_slice(subst::TypeSpace);
200 for predicate in predicates {
201 // (We do not need to worry about deep analysis of type
202 // expressions etc because the Drop impls are already forced
203 // to take on a structure that is roughly a alpha-renaming of
204 // the generic parameters of the item definition.)
205
206 // This path now just checks *all* predicates via the direct
207 // lookup, rather than using fulfill machinery.
208 //
209 // However, it may be more efficient in the future to batch
210 // the analysis together via the fulfill , rather than the
211 // repeated `contains` calls.
212
213 if !assumptions_in_impl_context.contains(&predicate) {
214 let item_span = tcx.map.span(self_type_did.node);
c34b1796 215 span_err!(tcx.sess, drop_impl_span, E0367,
62682a34 216 "The requirement `{}` is added only by the Drop impl.", predicate);
c34b1796
AL
217 tcx.sess.span_note(item_span,
218 "The same requirement must be part of \
219 the struct/enum definition");
220 }
221 }
85aaf69f 222
c34b1796
AL
223 if tcx.sess.has_errors() {
224 return Err(());
225 }
226 Ok(())
227}
85aaf69f 228
c34b1796
AL
229/// check_safety_of_destructor_if_necessary confirms that the type
230/// expression `typ` conforms to the "Drop Check Rule" from the Sound
231/// Generic Drop (RFC 769).
232///
233/// ----
234///
235/// The Drop Check Rule is the following:
236///
237/// Let `v` be some value (either temporary or named) and 'a be some
238/// lifetime (scope). If the type of `v` owns data of type `D`, where
239///
62682a34
SL
240/// * (1.) `D` has a lifetime- or type-parametric Drop implementation, and
241/// * (2.) the structure of `D` can reach a reference of type `&'a _`, and
242/// * (3.) either:
243/// * (A.) the Drop impl for `D` instantiates `D` at 'a directly,
c34b1796 244/// i.e. `D<'a>`, or,
62682a34 245/// * (B.) the Drop impl for `D` has some type parameter with a
c34b1796
AL
246/// trait bound `T` where `T` is a trait that has at least
247/// one method,
248///
249/// then 'a must strictly outlive the scope of v.
250///
251/// ----
252///
253/// This function is meant to by applied to the type for every
254/// expression in the program.
85aaf69f
SL
255pub fn check_safety_of_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>,
256 typ: ty::Ty<'tcx>,
257 span: Span,
258 scope: region::CodeExtent) {
62682a34
SL
259 debug!("check_safety_of_destructor_if_necessary typ: {:?} scope: {:?}",
260 typ, scope);
85aaf69f 261
c1a9b12d
SL
262 let parent_scope = rcx.tcx().region_maps.opt_encl_scope(scope).unwrap_or_else(|| {
263 rcx.tcx().sess.span_bug(
264 span, &format!("no enclosing scope found for scope: {:?}", scope))
265 });
85aaf69f 266
c34b1796 267 let result = iterate_over_potentially_unsafe_regions_in_type(
c1a9b12d
SL
268 &mut DropckContext {
269 rcx: rcx,
270 span: span,
271 parent_scope: parent_scope,
272 breadcrumbs: FnvHashSet()
273 },
c34b1796 274 TypeContext::Root,
85aaf69f 275 typ,
85aaf69f 276 0);
c34b1796
AL
277 match result {
278 Ok(()) => {}
279 Err(Error::Overflow(ref ctxt, ref detected_on_typ)) => {
280 let tcx = rcx.tcx();
281 span_err!(tcx.sess, span, E0320,
62682a34 282 "overflow while adding drop-check rules for {}", typ);
c34b1796
AL
283 match *ctxt {
284 TypeContext::Root => {
285 // no need for an additional note if the overflow
286 // was somehow on the root.
287 }
288 TypeContext::EnumVariant { def_id, variant, arg_index } => {
289 // FIXME (pnkfelix): eventually lookup arg_name
290 // for the given index on struct variants.
291 span_note!(
292 rcx.tcx().sess,
293 span,
294 "overflowed on enum {} variant {} argument {} type: {}",
c1a9b12d 295 tcx.item_path_str(def_id),
c34b1796
AL
296 variant,
297 arg_index,
62682a34 298 detected_on_typ);
c34b1796
AL
299 }
300 TypeContext::Struct { def_id, field } => {
301 span_note!(
302 rcx.tcx().sess,
303 span,
304 "overflowed on struct {} field {} type: {}",
c1a9b12d 305 tcx.item_path_str(def_id),
c34b1796 306 field,
62682a34 307 detected_on_typ);
c34b1796
AL
308 }
309 }
310 }
311 }
312}
313
314enum Error<'tcx> {
315 Overflow(TypeContext, ty::Ty<'tcx>),
85aaf69f
SL
316}
317
c1a9b12d 318#[derive(Copy, Clone)]
c34b1796
AL
319enum TypeContext {
320 Root,
321 EnumVariant {
322 def_id: ast::DefId,
323 variant: ast::Name,
324 arg_index: usize,
325 },
326 Struct {
327 def_id: ast::DefId,
328 field: ast::Name,
329 }
330}
331
c1a9b12d
SL
332struct DropckContext<'a, 'b: 'a, 'tcx: 'b> {
333 rcx: &'a mut Rcx<'b, 'tcx>,
334 /// types that have already been traversed
335 breadcrumbs: FnvHashSet<Ty<'tcx>>,
336 /// span for error reporting
85aaf69f 337 span: Span,
c1a9b12d
SL
338 /// the scope reachable dtorck types must outlive
339 parent_scope: region::CodeExtent
340}
341
342// `context` is used for reporting overflow errors
343fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'tcx>(
344 cx: &mut DropckContext<'a, 'b, 'tcx>,
345 context: TypeContext,
346 ty: Ty<'tcx>,
347 depth: usize) -> Result<(), Error<'tcx>>
85aaf69f 348{
c1a9b12d 349 let tcx = cx.rcx.tcx();
c34b1796
AL
350 // Issue #22443: Watch out for overflow. While we are careful to
351 // handle regular types properly, non-regular ones cause problems.
c1a9b12d
SL
352 let recursion_limit = tcx.sess.recursion_limit.get();
353 if depth / 4 >= recursion_limit {
354 // This can get into rather deep recursion, especially in the
355 // presence of things like Vec<T> -> Unique<T> -> PhantomData<T> -> T.
356 // use a higher recursion limit to avoid errors.
357 return Err(Error::Overflow(context, ty))
c34b1796
AL
358 }
359
c1a9b12d 360 let opt_phantom_data_def_id = tcx.lang_items.phantom_data();
85aaf69f 361
c1a9b12d
SL
362 if !cx.breadcrumbs.insert(ty) {
363 debug!("iterate_over_potentially_unsafe_regions_in_type \
364 {}ty: {} scope: {:?} - cached",
365 (0..depth).map(|_| ' ').collect::<String>(),
366 ty, cx.parent_scope);
367 return Ok(()); // we already visited this type
368 }
369 debug!("iterate_over_potentially_unsafe_regions_in_type \
370 {}ty: {} scope: {:?}",
371 (0..depth).map(|_| ' ').collect::<String>(),
372 ty, cx.parent_scope);
373
374 // If `typ` has a destructor, then we must ensure that all
375 // borrowed data reachable via `typ` must outlive the parent
376 // of `scope`. This is handled below.
377 //
378 // However, there is an important special case: by
379 // parametricity, any generic type parameters have *no* trait
380 // bounds in the Drop impl can not be used in any way (apart
381 // from being dropped), and thus we can treat data borrowed
382 // via such type parameters remains unreachable.
383 //
384 // For example, consider `impl<T> Drop for Vec<T> { ... }`,
385 // which does have to be able to drop instances of `T`, but
386 // otherwise cannot read data from `T`.
387 //
388 // Of course, for the type expression passed in for any such
389 // unbounded type parameter `T`, we must resume the recursive
390 // analysis on `T` (since it would be ignored by
391 // type_must_outlive).
392 //
393 // FIXME (pnkfelix): Long term, we could be smart and actually
394 // feed which generic parameters can be ignored *into* `fn
395 // type_must_outlive` (or some generalization thereof). But
396 // for the short term, it probably covers most cases of
397 // interest to just special case Drop impls where: (1.) there
398 // are no generic lifetime parameters and (2.) *all* generic
399 // type parameters are unbounded. If both conditions hold, we
400 // simply skip the `type_must_outlive` call entirely (but
401 // resume the recursive checking of the type-substructure).
402 if has_dtor_of_interest(tcx, ty, cx.span) {
403 debug!("iterate_over_potentially_unsafe_regions_in_type \
404 {}ty: {} - is a dtorck type!",
405 (0..depth).map(|_| ' ').collect::<String>(),
406 ty);
85aaf69f 407
c1a9b12d
SL
408 regionck::type_must_outlive(cx.rcx,
409 infer::SubregionOrigin::SafeDestructor(cx.span),
410 ty,
411 ty::ReScope(cx.parent_scope));
c34b1796 412
c1a9b12d
SL
413 return Ok(());
414 }
c34b1796 415
c1a9b12d
SL
416 debug!("iterate_over_potentially_unsafe_regions_in_type \
417 {}ty: {} scope: {:?} - checking interior",
418 (0..depth).map(|_| ' ').collect::<String>(),
419 ty, cx.parent_scope);
420
421 // We still need to ensure all referenced data is safe.
422 match ty.sty {
423 ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) |
424 ty::TyFloat(_) | ty::TyStr => {
425 // primitive - definitely safe
426 Ok(())
427 }
85aaf69f 428
c1a9b12d
SL
429 ty::TyBox(ity) | ty::TyArray(ity, _) | ty::TySlice(ity) => {
430 // single-element containers, behave like their element
431 iterate_over_potentially_unsafe_regions_in_type(
432 cx, context, ity, depth+1)
433 }
85aaf69f 434
c1a9b12d
SL
435 ty::TyStruct(did, substs) if Some(did) == opt_phantom_data_def_id => {
436 // PhantomData<T> - behaves identically to T
437 let ity = *substs.types.get(subst::TypeSpace, 0);
438 iterate_over_potentially_unsafe_regions_in_type(
439 cx, context, ity, depth+1)
440 }
85aaf69f 441
c1a9b12d
SL
442 ty::TyStruct(did, substs) => {
443 let fields = tcx.lookup_struct_fields(did);
444 for field in &fields {
445 let fty = tcx.lookup_field_type(did, field.id, substs);
446 let fty = cx.rcx.fcx.resolve_type_vars_if_possible(
447 cx.rcx.fcx.normalize_associated_types_in(cx.span, &fty));
448 try!(iterate_over_potentially_unsafe_regions_in_type(
449 cx,
450 TypeContext::Struct {
451 def_id: did,
452 field: field.name,
453 },
454 fty,
455 depth+1))
456 }
457 Ok(())
458 }
85aaf69f 459
c1a9b12d
SL
460 ty::TyEnum(did, substs) => {
461 let all_variant_info = tcx.substd_enum_variants(did, substs);
462 for variant_info in &all_variant_info {
463 for (i, fty) in variant_info.args.iter().enumerate() {
464 let fty = cx.rcx.fcx.resolve_type_vars_if_possible(
465 cx.rcx.fcx.normalize_associated_types_in(cx.span, &fty));
466 try!(iterate_over_potentially_unsafe_regions_in_type(
467 cx,
468 TypeContext::EnumVariant {
469 def_id: did,
470 variant: variant_info.name,
471 arg_index: i,
472 },
473 fty,
474 depth+1));
85aaf69f 475 }
c1a9b12d
SL
476 }
477 Ok(())
478 }
85aaf69f 479
c1a9b12d
SL
480 ty::TyTuple(ref tys) |
481 ty::TyClosure(_, box ty::ClosureSubsts { upvar_tys: ref tys, .. }) => {
482 for ty in tys {
483 try!(iterate_over_potentially_unsafe_regions_in_type(
484 cx, context, ty, depth+1))
485 }
486 Ok(())
85aaf69f 487 }
c34b1796 488
c1a9b12d
SL
489 ty::TyRawPtr(..) | ty::TyRef(..) | ty::TyParam(..) => {
490 // these always come with a witness of liveness (references
491 // explicitly, pointers implicitly, parameters by the
492 // caller).
493 Ok(())
494 }
bd371182 495
c1a9b12d
SL
496 ty::TyBareFn(..) => {
497 // FIXME(#26656): this type is always destruction-safe, but
498 // it implicitly witnesses Self: Fn, which can be false.
499 Ok(())
500 }
bd371182 501
c1a9b12d
SL
502 ty::TyInfer(..) | ty::TyError => {
503 tcx.sess.delay_span_bug(cx.span, "unresolved type in regionck");
504 Ok(())
505 }
bd371182 506
c1a9b12d
SL
507 // these are always dtorck
508 ty::TyTrait(..) | ty::TyProjection(_) => unreachable!(),
509 }
bd371182
AL
510}
511
512fn has_dtor_of_interest<'tcx>(tcx: &ty::ctxt<'tcx>,
c1a9b12d 513 ty: ty::Ty<'tcx>,
bd371182 514 span: Span) -> bool {
c1a9b12d
SL
515 match ty.sty {
516 ty::TyEnum(def_id, _) | ty::TyStruct(def_id, _) => {
517 let dtor_method_did = match tcx.destructor_for_type.borrow().get(&def_id) {
518 Some(def_id) => *def_id,
519 None => {
520 debug!("ty: {:?} has no dtor, and thus isn't a dropck type", ty);
521 return false;
bd371182 522 }
c1a9b12d
SL
523 };
524 let impl_did = tcx.impl_of_method(dtor_method_did)
bd371182
AL
525 .unwrap_or_else(|| {
526 tcx.sess.span_bug(
527 span, "no Drop impl found for drop method")
528 });
529
c1a9b12d 530 let dtor_typescheme = tcx.lookup_item_type(impl_did);
bd371182 531 let dtor_generics = dtor_typescheme.generics;
d9579d0f
AL
532
533 let mut has_pred_of_interest = false;
534
535 let mut seen_items = Vec::new();
536 let mut items_to_inspect = vec![impl_did];
537 'items: while let Some(item_def_id) = items_to_inspect.pop() {
538 if seen_items.contains(&item_def_id) {
539 continue;
540 }
541
c1a9b12d 542 for pred in tcx.lookup_predicates(item_def_id).predicates {
d9579d0f
AL
543 let result = match pred {
544 ty::Predicate::Equate(..) |
545 ty::Predicate::RegionOutlives(..) |
546 ty::Predicate::TypeOutlives(..) |
547 ty::Predicate::Projection(..) => {
548 // For now, assume all these where-clauses
549 // may give drop implementation capabilty
550 // to access borrowed data.
551 true
bd371182 552 }
bd371182 553
d9579d0f
AL
554 ty::Predicate::Trait(ty::Binder(ref t_pred)) => {
555 let def_id = t_pred.trait_ref.def_id;
c1a9b12d 556 if tcx.trait_items(def_id).len() != 0 {
d9579d0f
AL
557 // If trait has items, assume it adds
558 // capability to access borrowed data.
559 true
560 } else {
561 // Trait without items is itself
562 // uninteresting from POV of dropck.
563 //
564 // However, may have parent w/ items;
565 // so schedule checking of predicates,
566 items_to_inspect.push(def_id);
567 // and say "no capability found" for now.
568 false
569 }
570 }
571 };
572
573 if result {
574 has_pred_of_interest = true;
c1a9b12d
SL
575 debug!("ty: {:?} has interesting dtor due to generic preds, e.g. {:?}",
576 ty, pred);
d9579d0f
AL
577 break 'items;
578 }
bd371182
AL
579 }
580
d9579d0f
AL
581 seen_items.push(item_def_id);
582 }
bd371182
AL
583
584 // In `impl<'a> Drop ...`, we automatically assume
585 // `'a` is meaningful and thus represents a bound
586 // through which we could reach borrowed data.
587 //
588 // FIXME (pnkfelix): In the future it would be good to
589 // extend the language to allow the user to express,
590 // in the impl signature, that a lifetime is not
591 // actually used (something like `where 'a: ?Live`).
592 let has_region_param_of_interest =
593 dtor_generics.has_region_params(subst::TypeSpace);
594
c1a9b12d 595 let has_dtor_of_interest =
bd371182
AL
596 has_region_param_of_interest ||
597 has_pred_of_interest;
598
599 if has_dtor_of_interest {
c1a9b12d 600 debug!("ty: {:?} has interesting dtor, due to \
bd371182 601 region params: {} or pred: {}",
c1a9b12d 602 ty,
bd371182
AL
603 has_region_param_of_interest,
604 has_pred_of_interest);
605 } else {
c1a9b12d 606 debug!("ty: {:?} has dtor, but it is uninteresting", ty);
bd371182 607 }
c1a9b12d 608 has_dtor_of_interest
bd371182 609 }
c1a9b12d
SL
610 ty::TyTrait(..) | ty::TyProjection(..) => {
611 debug!("ty: {:?} isn't known, and therefore is a dropck type", ty);
612 true
613 },
614 _ => false
bd371182 615 }
bd371182 616}