]>
Commit | Line | Data |
---|---|---|
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 | ||
11 | use check::regionck::{self, Rcx}; | |
12 | ||
b039eaaf | 13 | use middle::def_id::DefId; |
e9174d1e | 14 | use middle::free_region::FreeRegionMap; |
85aaf69f SL |
15 | use middle::infer; |
16 | use middle::region; | |
c34b1796 | 17 | use middle::subst::{self, Subst}; |
e9174d1e | 18 | use middle::traits; |
85aaf69f | 19 | use middle::ty::{self, Ty}; |
c1a9b12d | 20 | use util::nodemap::FnvHashSet; |
c34b1796 AL |
21 | |
22 | use syntax::ast; | |
23 | use syntax::codemap::{self, Span}; | |
e9174d1e | 24 | use syntax::parse::token::special_idents; |
c34b1796 AL |
25 | |
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). | |
29 | /// | |
30 | /// This means: | |
31 | /// | |
32 | /// 1. The self type must be nominal (this is already checked during | |
33 | /// coherence), | |
34 | /// | |
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, | |
38 | /// | |
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> { ... }`). | |
42 | /// | |
e9174d1e | 43 | pub fn check_drop_impl(tcx: &ty::ctxt, drop_impl_did: DefId) -> Result<(), ()> { |
c34b1796 | 44 | let ty::TypeScheme { generics: ref dtor_generics, |
c1a9b12d SL |
45 | ty: dtor_self_type } = tcx.lookup_item_type(drop_impl_did); |
46 | let dtor_predicates = tcx.lookup_predicates(drop_impl_did); | |
c34b1796 | 47 | match dtor_self_type.sty { |
e9174d1e SL |
48 | ty::TyEnum(adt_def, self_to_impl_substs) | |
49 | ty::TyStruct(adt_def, self_to_impl_substs) => { | |
c34b1796 AL |
50 | try!(ensure_drop_params_and_item_params_correspond(tcx, |
51 | drop_impl_did, | |
52 | dtor_generics, | |
62682a34 | 53 | &dtor_self_type, |
e9174d1e | 54 | adt_def.did)); |
c34b1796 AL |
55 | |
56 | ensure_drop_predicates_are_implied_by_item_defn(tcx, | |
57 | drop_impl_did, | |
58 | &dtor_predicates, | |
e9174d1e | 59 | adt_def.did, |
c34b1796 AL |
60 | self_to_impl_substs) |
61 | } | |
62 | _ => { | |
63 | // Destructors only work on nominal types. This was | |
64 | // already checked by coherence, so we can panic here. | |
65 | let span = tcx.map.def_id_span(drop_impl_did, codemap::DUMMY_SP); | |
66 | tcx.sess.span_bug( | |
67 | span, &format!("should have been rejected by coherence check: {}", | |
62682a34 | 68 | dtor_self_type)); |
c34b1796 AL |
69 | } |
70 | } | |
71 | } | |
72 | ||
73 | fn ensure_drop_params_and_item_params_correspond<'tcx>( | |
74 | tcx: &ty::ctxt<'tcx>, | |
e9174d1e | 75 | drop_impl_did: DefId, |
c34b1796 AL |
76 | drop_impl_generics: &ty::Generics<'tcx>, |
77 | drop_impl_ty: &ty::Ty<'tcx>, | |
e9174d1e | 78 | self_type_did: DefId) -> Result<(), ()> |
c34b1796 | 79 | { |
b039eaaf SL |
80 | let drop_impl_node_id = tcx.map.as_local_node_id(drop_impl_did).unwrap(); |
81 | let self_type_node_id = tcx.map.as_local_node_id(self_type_did).unwrap(); | |
e9174d1e SL |
82 | |
83 | // check that the impl type can be made to match the trait type. | |
84 | ||
b039eaaf | 85 | let impl_param_env = ty::ParameterEnvironment::for_item(tcx, self_type_node_id); |
e9174d1e SL |
86 | let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(impl_param_env), true); |
87 | ||
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); | |
90 | ||
91 | let drop_impl_span = tcx.map.def_id_span(drop_impl_did, codemap::DUMMY_SP); | |
92 | let fresh_impl_substs = | |
93 | infcx.fresh_substs_for_generics(drop_impl_span, drop_impl_generics); | |
94 | let fresh_impl_self_ty = drop_impl_ty.subst(tcx, &fresh_impl_substs); | |
c34b1796 | 95 | |
e9174d1e SL |
96 | if let Err(_) = infer::mk_eqty(&infcx, true, infer::TypeOrigin::Misc(drop_impl_span), |
97 | named_type, fresh_impl_self_ty) { | |
b039eaaf | 98 | let item_span = tcx.map.span(self_type_node_id); |
9cc50fc6 SL |
99 | struct_span_err!(tcx.sess, drop_impl_span, E0366, |
100 | "Implementations of Drop cannot be specialized") | |
101 | .span_note(item_span, | |
102 | "Use same sequence of generic type and region \ | |
103 | parameters that is on the struct/enum definition") | |
104 | .emit(); | |
c34b1796 | 105 | return Err(()); |
e9174d1e SL |
106 | } |
107 | ||
108 | if let Err(ref errors) = infcx.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) { | |
109 | // this could be reached when we get lazy normalization | |
110 | traits::report_fulfillment_errors(&infcx, errors); | |
111 | return Err(()); | |
112 | } | |
113 | ||
114 | let free_regions = FreeRegionMap::new(); | |
b039eaaf | 115 | infcx.resolve_regions_and_report_errors(&free_regions, drop_impl_node_id); |
e9174d1e | 116 | Ok(()) |
c34b1796 AL |
117 | } |
118 | ||
119 | /// Confirms that every predicate imposed by dtor_predicates is | |
120 | /// implied by assuming the predicates attached to self_type_did. | |
121 | fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>( | |
122 | tcx: &ty::ctxt<'tcx>, | |
e9174d1e | 123 | drop_impl_did: DefId, |
c34b1796 | 124 | dtor_predicates: &ty::GenericPredicates<'tcx>, |
e9174d1e | 125 | self_type_did: DefId, |
c34b1796 AL |
126 | self_to_impl_substs: &subst::Substs<'tcx>) -> Result<(), ()> { |
127 | ||
128 | // Here is an example, analogous to that from | |
129 | // `compare_impl_method`. | |
130 | // | |
131 | // Consider a struct type: | |
132 | // | |
133 | // struct Type<'c, 'b:'c, 'a> { | |
134 | // x: &'a Contents // (contents are irrelevant; | |
135 | // y: &'c Cell<&'b Contents>, // only the bounds matter for our purposes.) | |
136 | // } | |
137 | // | |
138 | // and a Drop impl: | |
139 | // | |
140 | // impl<'z, 'y:'z, 'x:'y> Drop for P<'z, 'y, 'x> { | |
141 | // fn drop(&mut self) { self.y.set(self.x); } // (only legal if 'x: 'y) | |
142 | // } | |
143 | // | |
144 | // We start out with self_to_impl_substs, that maps the generic | |
145 | // parameters of Type to that of the Drop impl. | |
146 | // | |
147 | // self_to_impl_substs = {'c => 'z, 'b => 'y, 'a => 'x} | |
148 | // | |
149 | // Applying this to the predicates (i.e. assumptions) provided by the item | |
150 | // definition yields the instantiated assumptions: | |
151 | // | |
152 | // ['y : 'z] | |
153 | // | |
154 | // We then check all of the predicates of the Drop impl: | |
155 | // | |
156 | // ['y:'z, 'x:'y] | |
157 | // | |
158 | // and ensure each is in the list of instantiated | |
159 | // assumptions. Here, `'y:'z` is present, but `'x:'y` is | |
160 | // absent. So we report an error that the Drop impl injected a | |
161 | // predicate that is not present on the struct definition. | |
162 | ||
b039eaaf | 163 | let self_type_node_id = tcx.map.as_local_node_id(self_type_did).unwrap(); |
c34b1796 AL |
164 | |
165 | let drop_impl_span = tcx.map.def_id_span(drop_impl_did, codemap::DUMMY_SP); | |
166 | ||
167 | // We can assume the predicates attached to struct/enum definition | |
168 | // hold. | |
c1a9b12d | 169 | let generic_assumptions = tcx.lookup_predicates(self_type_did); |
c34b1796 AL |
170 | |
171 | let assumptions_in_impl_context = generic_assumptions.instantiate(tcx, &self_to_impl_substs); | |
172 | assert!(assumptions_in_impl_context.predicates.is_empty_in(subst::SelfSpace)); | |
173 | assert!(assumptions_in_impl_context.predicates.is_empty_in(subst::FnSpace)); | |
174 | let assumptions_in_impl_context = | |
175 | assumptions_in_impl_context.predicates.get_slice(subst::TypeSpace); | |
176 | ||
177 | // An earlier version of this code attempted to do this checking | |
178 | // via the traits::fulfill machinery. However, it ran into trouble | |
179 | // since the fulfill machinery merely turns outlives-predicates | |
180 | // 'a:'b and T:'b into region inference constraints. It is simpler | |
181 | // just to look for all the predicates directly. | |
182 | ||
183 | assert!(dtor_predicates.predicates.is_empty_in(subst::SelfSpace)); | |
184 | assert!(dtor_predicates.predicates.is_empty_in(subst::FnSpace)); | |
185 | let predicates = dtor_predicates.predicates.get_slice(subst::TypeSpace); | |
186 | for predicate in predicates { | |
187 | // (We do not need to worry about deep analysis of type | |
188 | // expressions etc because the Drop impls are already forced | |
b039eaaf | 189 | // to take on a structure that is roughly an alpha-renaming of |
c34b1796 AL |
190 | // the generic parameters of the item definition.) |
191 | ||
192 | // This path now just checks *all* predicates via the direct | |
193 | // lookup, rather than using fulfill machinery. | |
194 | // | |
195 | // However, it may be more efficient in the future to batch | |
196 | // the analysis together via the fulfill , rather than the | |
197 | // repeated `contains` calls. | |
198 | ||
199 | if !assumptions_in_impl_context.contains(&predicate) { | |
b039eaaf | 200 | let item_span = tcx.map.span(self_type_node_id); |
9cc50fc6 SL |
201 | struct_span_err!(tcx.sess, drop_impl_span, E0367, |
202 | "The requirement `{}` is added only by the Drop impl.", predicate) | |
203 | .span_note(item_span, | |
204 | "The same requirement must be part of \ | |
205 | the struct/enum definition") | |
206 | .emit(); | |
c34b1796 AL |
207 | } |
208 | } | |
85aaf69f | 209 | |
c34b1796 AL |
210 | if tcx.sess.has_errors() { |
211 | return Err(()); | |
212 | } | |
213 | Ok(()) | |
214 | } | |
85aaf69f | 215 | |
c34b1796 AL |
216 | /// check_safety_of_destructor_if_necessary confirms that the type |
217 | /// expression `typ` conforms to the "Drop Check Rule" from the Sound | |
218 | /// Generic Drop (RFC 769). | |
219 | /// | |
220 | /// ---- | |
221 | /// | |
b039eaaf | 222 | /// The simplified (*) Drop Check Rule is the following: |
c34b1796 AL |
223 | /// |
224 | /// Let `v` be some value (either temporary or named) and 'a be some | |
225 | /// lifetime (scope). If the type of `v` owns data of type `D`, where | |
226 | /// | |
b039eaaf SL |
227 | /// * (1.) `D` has a lifetime- or type-parametric Drop implementation, |
228 | /// (where that `Drop` implementation does not opt-out of | |
229 | /// this check via the `unsafe_destructor_blind_to_params` | |
230 | /// attribute), and | |
231 | /// * (2.) the structure of `D` can reach a reference of type `&'a _`, | |
c34b1796 AL |
232 | /// |
233 | /// then 'a must strictly outlive the scope of v. | |
234 | /// | |
235 | /// ---- | |
236 | /// | |
237 | /// This function is meant to by applied to the type for every | |
238 | /// expression in the program. | |
b039eaaf SL |
239 | /// |
240 | /// ---- | |
241 | /// | |
242 | /// (*) The qualifier "simplified" is attached to the above | |
243 | /// definition of the Drop Check Rule, because it is a simplification | |
244 | /// of the original Drop Check rule, which attempted to prove that | |
245 | /// some `Drop` implementations could not possibly access data even if | |
246 | /// it was technically reachable, due to parametricity. | |
247 | /// | |
248 | /// However, (1.) parametricity on its own turned out to be a | |
249 | /// necessary but insufficient condition, and (2.) future changes to | |
250 | /// the language are expected to make it impossible to ensure that a | |
251 | /// `Drop` implementation is actually parametric with respect to any | |
252 | /// particular type parameter. (In particular, impl specialization is | |
253 | /// expected to break the needed parametricity property beyond | |
254 | /// repair.) | |
255 | /// | |
256 | /// Therefore we have scaled back Drop-Check to a more conservative | |
257 | /// rule that does not attempt to deduce whether a `Drop` | |
258 | /// implementation could not possible access data of a given lifetime; | |
259 | /// instead Drop-Check now simply assumes that if a destructor has | |
260 | /// access (direct or indirect) to a lifetime parameter, then that | |
261 | /// lifetime must be forced to outlive that destructor's dynamic | |
262 | /// extent. We then provide the `unsafe_destructor_blind_to_params` | |
263 | /// attribute as a way for destructor implementations to opt-out of | |
264 | /// this conservative assumption (and thus assume the obligation of | |
265 | /// ensuring that they do not access data nor invoke methods of | |
266 | /// values that have been previously dropped). | |
267 | /// | |
85aaf69f | 268 | pub fn check_safety_of_destructor_if_necessary<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>, |
e9174d1e SL |
269 | typ: ty::Ty<'tcx>, |
270 | span: Span, | |
271 | scope: region::CodeExtent) { | |
62682a34 SL |
272 | debug!("check_safety_of_destructor_if_necessary typ: {:?} scope: {:?}", |
273 | typ, scope); | |
85aaf69f | 274 | |
c1a9b12d SL |
275 | let parent_scope = rcx.tcx().region_maps.opt_encl_scope(scope).unwrap_or_else(|| { |
276 | rcx.tcx().sess.span_bug( | |
277 | span, &format!("no enclosing scope found for scope: {:?}", scope)) | |
278 | }); | |
85aaf69f | 279 | |
c34b1796 | 280 | let result = iterate_over_potentially_unsafe_regions_in_type( |
c1a9b12d SL |
281 | &mut DropckContext { |
282 | rcx: rcx, | |
283 | span: span, | |
284 | parent_scope: parent_scope, | |
285 | breadcrumbs: FnvHashSet() | |
286 | }, | |
c34b1796 | 287 | TypeContext::Root, |
85aaf69f | 288 | typ, |
85aaf69f | 289 | 0); |
c34b1796 AL |
290 | match result { |
291 | Ok(()) => {} | |
292 | Err(Error::Overflow(ref ctxt, ref detected_on_typ)) => { | |
293 | let tcx = rcx.tcx(); | |
9cc50fc6 SL |
294 | let mut err = struct_span_err!(tcx.sess, span, E0320, |
295 | "overflow while adding drop-check rules for {}", typ); | |
c34b1796 AL |
296 | match *ctxt { |
297 | TypeContext::Root => { | |
298 | // no need for an additional note if the overflow | |
299 | // was somehow on the root. | |
300 | } | |
e9174d1e SL |
301 | TypeContext::ADT { def_id, variant, field, field_index } => { |
302 | let adt = tcx.lookup_adt_def(def_id); | |
303 | let variant_name = match adt.adt_kind() { | |
304 | ty::AdtKind::Enum => format!("enum {} variant {}", | |
305 | tcx.item_path_str(def_id), | |
306 | variant), | |
307 | ty::AdtKind::Struct => format!("struct {}", | |
308 | tcx.item_path_str(def_id)) | |
309 | }; | |
310 | let field_name = if field == special_idents::unnamed_field.name { | |
311 | format!("#{}", field_index) | |
312 | } else { | |
313 | format!("`{}`", field) | |
314 | }; | |
c34b1796 | 315 | span_note!( |
9cc50fc6 | 316 | &mut err, |
c34b1796 | 317 | span, |
e9174d1e SL |
318 | "overflowed on {} field {} type: {}", |
319 | variant_name, | |
320 | field_name, | |
62682a34 | 321 | detected_on_typ); |
c34b1796 AL |
322 | } |
323 | } | |
9cc50fc6 | 324 | err.emit(); |
c34b1796 AL |
325 | } |
326 | } | |
327 | } | |
328 | ||
329 | enum Error<'tcx> { | |
330 | Overflow(TypeContext, ty::Ty<'tcx>), | |
85aaf69f SL |
331 | } |
332 | ||
c1a9b12d | 333 | #[derive(Copy, Clone)] |
c34b1796 AL |
334 | enum TypeContext { |
335 | Root, | |
e9174d1e SL |
336 | ADT { |
337 | def_id: DefId, | |
c34b1796 | 338 | variant: ast::Name, |
c34b1796 | 339 | field: ast::Name, |
e9174d1e | 340 | field_index: usize |
c34b1796 AL |
341 | } |
342 | } | |
343 | ||
c1a9b12d SL |
344 | struct DropckContext<'a, 'b: 'a, 'tcx: 'b> { |
345 | rcx: &'a mut Rcx<'b, 'tcx>, | |
346 | /// types that have already been traversed | |
347 | breadcrumbs: FnvHashSet<Ty<'tcx>>, | |
348 | /// span for error reporting | |
85aaf69f | 349 | span: Span, |
c1a9b12d SL |
350 | /// the scope reachable dtorck types must outlive |
351 | parent_scope: region::CodeExtent | |
352 | } | |
353 | ||
354 | // `context` is used for reporting overflow errors | |
355 | fn iterate_over_potentially_unsafe_regions_in_type<'a, 'b, 'tcx>( | |
356 | cx: &mut DropckContext<'a, 'b, 'tcx>, | |
357 | context: TypeContext, | |
358 | ty: Ty<'tcx>, | |
359 | depth: usize) -> Result<(), Error<'tcx>> | |
85aaf69f | 360 | { |
c1a9b12d | 361 | let tcx = cx.rcx.tcx(); |
c34b1796 AL |
362 | // Issue #22443: Watch out for overflow. While we are careful to |
363 | // handle regular types properly, non-regular ones cause problems. | |
c1a9b12d SL |
364 | let recursion_limit = tcx.sess.recursion_limit.get(); |
365 | if depth / 4 >= recursion_limit { | |
366 | // This can get into rather deep recursion, especially in the | |
367 | // presence of things like Vec<T> -> Unique<T> -> PhantomData<T> -> T. | |
368 | // use a higher recursion limit to avoid errors. | |
369 | return Err(Error::Overflow(context, ty)) | |
c34b1796 AL |
370 | } |
371 | ||
9cc50fc6 SL |
372 | // canoncialize the regions in `ty` before inserting - infinitely many |
373 | // region variables can refer to the same region. | |
374 | let ty = cx.rcx.infcx().resolve_type_and_region_vars_if_possible(&ty); | |
375 | ||
c1a9b12d SL |
376 | if !cx.breadcrumbs.insert(ty) { |
377 | debug!("iterate_over_potentially_unsafe_regions_in_type \ | |
378 | {}ty: {} scope: {:?} - cached", | |
379 | (0..depth).map(|_| ' ').collect::<String>(), | |
380 | ty, cx.parent_scope); | |
381 | return Ok(()); // we already visited this type | |
382 | } | |
383 | debug!("iterate_over_potentially_unsafe_regions_in_type \ | |
384 | {}ty: {} scope: {:?}", | |
385 | (0..depth).map(|_| ' ').collect::<String>(), | |
386 | ty, cx.parent_scope); | |
387 | ||
388 | // If `typ` has a destructor, then we must ensure that all | |
389 | // borrowed data reachable via `typ` must outlive the parent | |
390 | // of `scope`. This is handled below. | |
391 | // | |
b039eaaf SL |
392 | // However, there is an important special case: for any Drop |
393 | // impl that is tagged as "blind" to their parameters, | |
394 | // we assume that data borrowed via such type parameters | |
395 | // remains unreachable via that Drop impl. | |
396 | // | |
397 | // For example, consider: | |
398 | // | |
399 | // ```rust | |
400 | // #[unsafe_destructor_blind_to_params] | |
401 | // impl<T> Drop for Vec<T> { ... } | |
402 | // ``` | |
c1a9b12d | 403 | // |
c1a9b12d SL |
404 | // which does have to be able to drop instances of `T`, but |
405 | // otherwise cannot read data from `T`. | |
406 | // | |
407 | // Of course, for the type expression passed in for any such | |
408 | // unbounded type parameter `T`, we must resume the recursive | |
409 | // analysis on `T` (since it would be ignored by | |
410 | // type_must_outlive). | |
e9174d1e | 411 | if has_dtor_of_interest(tcx, ty) { |
c1a9b12d SL |
412 | debug!("iterate_over_potentially_unsafe_regions_in_type \ |
413 | {}ty: {} - is a dtorck type!", | |
414 | (0..depth).map(|_| ' ').collect::<String>(), | |
415 | ty); | |
85aaf69f | 416 | |
c1a9b12d SL |
417 | regionck::type_must_outlive(cx.rcx, |
418 | infer::SubregionOrigin::SafeDestructor(cx.span), | |
419 | ty, | |
420 | ty::ReScope(cx.parent_scope)); | |
c34b1796 | 421 | |
c1a9b12d SL |
422 | return Ok(()); |
423 | } | |
c34b1796 | 424 | |
c1a9b12d SL |
425 | debug!("iterate_over_potentially_unsafe_regions_in_type \ |
426 | {}ty: {} scope: {:?} - checking interior", | |
427 | (0..depth).map(|_| ' ').collect::<String>(), | |
428 | ty, cx.parent_scope); | |
429 | ||
430 | // We still need to ensure all referenced data is safe. | |
431 | match ty.sty { | |
432 | ty::TyBool | ty::TyChar | ty::TyInt(_) | ty::TyUint(_) | | |
433 | ty::TyFloat(_) | ty::TyStr => { | |
434 | // primitive - definitely safe | |
435 | Ok(()) | |
436 | } | |
85aaf69f | 437 | |
c1a9b12d SL |
438 | ty::TyBox(ity) | ty::TyArray(ity, _) | ty::TySlice(ity) => { |
439 | // single-element containers, behave like their element | |
440 | iterate_over_potentially_unsafe_regions_in_type( | |
441 | cx, context, ity, depth+1) | |
442 | } | |
85aaf69f | 443 | |
e9174d1e | 444 | ty::TyStruct(def, substs) if def.is_phantom_data() => { |
c1a9b12d SL |
445 | // PhantomData<T> - behaves identically to T |
446 | let ity = *substs.types.get(subst::TypeSpace, 0); | |
447 | iterate_over_potentially_unsafe_regions_in_type( | |
448 | cx, context, ity, depth+1) | |
449 | } | |
85aaf69f | 450 | |
e9174d1e SL |
451 | ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => { |
452 | let did = def.did; | |
453 | for variant in &def.variants { | |
454 | for (i, field) in variant.fields.iter().enumerate() { | |
455 | let fty = field.ty(tcx, substs); | |
c1a9b12d SL |
456 | let fty = cx.rcx.fcx.resolve_type_vars_if_possible( |
457 | cx.rcx.fcx.normalize_associated_types_in(cx.span, &fty)); | |
458 | try!(iterate_over_potentially_unsafe_regions_in_type( | |
459 | cx, | |
e9174d1e | 460 | TypeContext::ADT { |
c1a9b12d | 461 | def_id: did, |
e9174d1e SL |
462 | field: field.name, |
463 | variant: variant.name, | |
464 | field_index: i | |
c1a9b12d SL |
465 | }, |
466 | fty, | |
e9174d1e | 467 | depth+1)) |
85aaf69f | 468 | } |
c1a9b12d SL |
469 | } |
470 | Ok(()) | |
471 | } | |
85aaf69f | 472 | |
c1a9b12d SL |
473 | ty::TyTuple(ref tys) | |
474 | ty::TyClosure(_, box ty::ClosureSubsts { upvar_tys: ref tys, .. }) => { | |
475 | for ty in tys { | |
476 | try!(iterate_over_potentially_unsafe_regions_in_type( | |
477 | cx, context, ty, depth+1)) | |
478 | } | |
479 | Ok(()) | |
85aaf69f | 480 | } |
c34b1796 | 481 | |
c1a9b12d SL |
482 | ty::TyRawPtr(..) | ty::TyRef(..) | ty::TyParam(..) => { |
483 | // these always come with a witness of liveness (references | |
484 | // explicitly, pointers implicitly, parameters by the | |
485 | // caller). | |
486 | Ok(()) | |
487 | } | |
bd371182 | 488 | |
c1a9b12d SL |
489 | ty::TyBareFn(..) => { |
490 | // FIXME(#26656): this type is always destruction-safe, but | |
491 | // it implicitly witnesses Self: Fn, which can be false. | |
492 | Ok(()) | |
493 | } | |
bd371182 | 494 | |
c1a9b12d SL |
495 | ty::TyInfer(..) | ty::TyError => { |
496 | tcx.sess.delay_span_bug(cx.span, "unresolved type in regionck"); | |
497 | Ok(()) | |
498 | } | |
bd371182 | 499 | |
c1a9b12d SL |
500 | // these are always dtorck |
501 | ty::TyTrait(..) | ty::TyProjection(_) => unreachable!(), | |
502 | } | |
bd371182 AL |
503 | } |
504 | ||
505 | fn has_dtor_of_interest<'tcx>(tcx: &ty::ctxt<'tcx>, | |
e9174d1e | 506 | ty: ty::Ty<'tcx>) -> bool { |
c1a9b12d | 507 | match ty.sty { |
e9174d1e SL |
508 | ty::TyEnum(def, _) | ty::TyStruct(def, _) => { |
509 | def.is_dtorck(tcx) | |
bd371182 | 510 | } |
c1a9b12d SL |
511 | ty::TyTrait(..) | ty::TyProjection(..) => { |
512 | debug!("ty: {:?} isn't known, and therefore is a dropck type", ty); | |
513 | true | |
514 | }, | |
515 | _ => false | |
bd371182 | 516 | } |
bd371182 | 517 | } |