]> git.proxmox.com Git - rustc.git/blob - src/librustc_trans/trans/glue.rs
Imported Upstream version 1.3.0+dfsg1
[rustc.git] / src / librustc_trans / trans / glue.rs
1 // Copyright 2012-2013 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 //!
12 //
13 // Code relating to drop glue.
14
15
16 use back::abi;
17 use back::link::*;
18 use llvm;
19 use llvm::{ValueRef, get_param};
20 use metadata::csearch;
21 use middle::lang_items::ExchangeFreeFnLangItem;
22 use middle::subst;
23 use middle::subst::{Subst, Substs};
24 use middle::ty::{self, Ty};
25 use trans::adt;
26 use trans::adt::GetDtorType; // for tcx.dtor_type()
27 use trans::base::*;
28 use trans::build::*;
29 use trans::callee;
30 use trans::cleanup;
31 use trans::cleanup::CleanupMethods;
32 use trans::common::*;
33 use trans::debuginfo::DebugLoc;
34 use trans::declare;
35 use trans::expr;
36 use trans::foreign;
37 use trans::inline;
38 use trans::machine::*;
39 use trans::monomorphize;
40 use trans::type_of::{type_of, type_of_dtor, sizing_type_of, align_of};
41 use trans::type_::Type;
42
43 use arena::TypedArena;
44 use libc::c_uint;
45 use syntax::ast;
46
47 pub fn trans_exchange_free_dyn<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
48 v: ValueRef,
49 size: ValueRef,
50 align: ValueRef,
51 debug_loc: DebugLoc)
52 -> Block<'blk, 'tcx> {
53 let _icx = push_ctxt("trans_exchange_free");
54 let ccx = cx.ccx();
55 callee::trans_lang_call(cx,
56 langcall(cx, None, "", ExchangeFreeFnLangItem),
57 &[PointerCast(cx, v, Type::i8p(ccx)), size, align],
58 Some(expr::Ignore),
59 debug_loc).bcx
60 }
61
62 pub fn trans_exchange_free<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
63 v: ValueRef,
64 size: u64,
65 align: u32,
66 debug_loc: DebugLoc)
67 -> Block<'blk, 'tcx> {
68 trans_exchange_free_dyn(cx,
69 v,
70 C_uint(cx.ccx(), size),
71 C_uint(cx.ccx(), align),
72 debug_loc)
73 }
74
75 pub fn trans_exchange_free_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
76 ptr: ValueRef,
77 content_ty: Ty<'tcx>,
78 debug_loc: DebugLoc)
79 -> Block<'blk, 'tcx> {
80 assert!(type_is_sized(bcx.ccx().tcx(), content_ty));
81 let sizing_type = sizing_type_of(bcx.ccx(), content_ty);
82 let content_size = llsize_of_alloc(bcx.ccx(), sizing_type);
83
84 // `Box<ZeroSizeType>` does not allocate.
85 if content_size != 0 {
86 let content_align = align_of(bcx.ccx(), content_ty);
87 trans_exchange_free(bcx, ptr, content_size, content_align, debug_loc)
88 } else {
89 bcx
90 }
91 }
92
93 pub fn get_drop_glue_type<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
94 t: Ty<'tcx>) -> Ty<'tcx> {
95 let tcx = ccx.tcx();
96 // Even if there is no dtor for t, there might be one deeper down and we
97 // might need to pass in the vtable ptr.
98 if !type_is_sized(tcx, t) {
99 return t
100 }
101
102 // FIXME (#22815): note that type_needs_drop conservatively
103 // approximates in some cases and may say a type expression
104 // requires drop glue when it actually does not.
105 //
106 // (In this case it is not clear whether any harm is done, i.e.
107 // erroneously returning `t` in some cases where we could have
108 // returned `tcx.types.i8` does not appear unsound. The impact on
109 // code quality is unknown at this time.)
110
111 if !type_needs_drop(tcx, t) {
112 return tcx.types.i8;
113 }
114 match t.sty {
115 ty::TyBox(typ) if !type_needs_drop(tcx, typ)
116 && type_is_sized(tcx, typ) => {
117 let llty = sizing_type_of(ccx, typ);
118 // `Box<ZeroSizeType>` does not allocate.
119 if llsize_of_alloc(ccx, llty) == 0 {
120 tcx.types.i8
121 } else {
122 t
123 }
124 }
125 _ => t
126 }
127 }
128
129 pub fn drop_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
130 v: ValueRef,
131 t: Ty<'tcx>,
132 debug_loc: DebugLoc) -> Block<'blk, 'tcx> {
133 drop_ty_core(bcx, v, t, debug_loc, false, None)
134 }
135
136 pub fn drop_ty_core<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
137 v: ValueRef,
138 t: Ty<'tcx>,
139 debug_loc: DebugLoc,
140 skip_dtor: bool,
141 drop_hint: Option<cleanup::DropHintValue>)
142 -> Block<'blk, 'tcx> {
143 // NB: v is an *alias* of type t here, not a direct value.
144 debug!("drop_ty_core(t={:?}, skip_dtor={} drop_hint={:?})", t, skip_dtor, drop_hint);
145 let _icx = push_ctxt("drop_ty");
146 let mut bcx = bcx;
147 if bcx.fcx.type_needs_drop(t) {
148 let ccx = bcx.ccx();
149 let g = if skip_dtor {
150 DropGlueKind::TyContents(t)
151 } else {
152 DropGlueKind::Ty(t)
153 };
154 let glue = get_drop_glue_core(ccx, g);
155 let glue_type = get_drop_glue_type(ccx, t);
156 let ptr = if glue_type != t {
157 PointerCast(bcx, v, type_of(ccx, glue_type).ptr_to())
158 } else {
159 v
160 };
161
162 match drop_hint {
163 Some(drop_hint) => {
164 let hint_val = load_ty(bcx, drop_hint.value(), bcx.tcx().types.u8);
165 let moved_val =
166 C_integral(Type::i8(bcx.ccx()), adt::DTOR_MOVED_HINT as u64, false);
167 let may_need_drop =
168 ICmp(bcx, llvm::IntNE, hint_val, moved_val, DebugLoc::None);
169 bcx = with_cond(bcx, may_need_drop, |cx| {
170 Call(cx, glue, &[ptr], None, debug_loc);
171 cx
172 })
173 }
174 None => {
175 // No drop-hint ==> call standard drop glue
176 Call(bcx, glue, &[ptr], None, debug_loc);
177 }
178 }
179 }
180 bcx
181 }
182
183 pub fn drop_ty_immediate<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
184 v: ValueRef,
185 t: Ty<'tcx>,
186 debug_loc: DebugLoc,
187 skip_dtor: bool)
188 -> Block<'blk, 'tcx> {
189 let _icx = push_ctxt("drop_ty_immediate");
190 let vp = alloca(bcx, type_of(bcx.ccx(), t), "");
191 store_ty(bcx, v, vp, t);
192 drop_ty_core(bcx, vp, t, debug_loc, skip_dtor, None)
193 }
194
195 pub fn get_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> ValueRef {
196 get_drop_glue_core(ccx, DropGlueKind::Ty(t))
197 }
198
199 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
200 pub enum DropGlueKind<'tcx> {
201 /// The normal path; runs the dtor, and then recurs on the contents
202 Ty(Ty<'tcx>),
203 /// Skips the dtor, if any, for ty; drops the contents directly.
204 /// Note that the dtor is only skipped at the most *shallow*
205 /// level, namely, an `impl Drop for Ty` itself. So, for example,
206 /// if Ty is Newtype(S) then only the Drop impl for for Newtype
207 /// itself will be skipped, while the Drop impl for S, if any,
208 /// will be invoked.
209 TyContents(Ty<'tcx>),
210 }
211
212 impl<'tcx> DropGlueKind<'tcx> {
213 fn ty(&self) -> Ty<'tcx> {
214 match *self { DropGlueKind::Ty(t) | DropGlueKind::TyContents(t) => t }
215 }
216
217 fn map_ty<F>(&self, mut f: F) -> DropGlueKind<'tcx> where F: FnMut(Ty<'tcx>) -> Ty<'tcx>
218 {
219 match *self {
220 DropGlueKind::Ty(t) => DropGlueKind::Ty(f(t)),
221 DropGlueKind::TyContents(t) => DropGlueKind::TyContents(f(t)),
222 }
223 }
224 }
225
226 fn get_drop_glue_core<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
227 g: DropGlueKind<'tcx>) -> ValueRef {
228 debug!("make drop glue for {:?}", g);
229 let g = g.map_ty(|t| get_drop_glue_type(ccx, t));
230 debug!("drop glue type {:?}", g);
231 match ccx.drop_glues().borrow().get(&g) {
232 Some(&glue) => return glue,
233 _ => { }
234 }
235 let t = g.ty();
236
237 let llty = if type_is_sized(ccx.tcx(), t) {
238 type_of(ccx, t).ptr_to()
239 } else {
240 type_of(ccx, ccx.tcx().mk_box(t)).ptr_to()
241 };
242
243 let llfnty = Type::glue_fn(ccx, llty);
244
245 // To avoid infinite recursion, don't `make_drop_glue` until after we've
246 // added the entry to the `drop_glues` cache.
247 if let Some(old_sym) = ccx.available_drop_glues().borrow().get(&g) {
248 let llfn = declare::declare_cfn(ccx, &old_sym, llfnty, ccx.tcx().mk_nil());
249 ccx.drop_glues().borrow_mut().insert(g, llfn);
250 return llfn;
251 };
252
253 let fn_nm = mangle_internal_name_by_type_and_seq(ccx, t, "drop");
254 let llfn = declare::define_cfn(ccx, &fn_nm, llfnty, ccx.tcx().mk_nil()).unwrap_or_else(||{
255 ccx.sess().bug(&format!("symbol `{}` already defined", fn_nm));
256 });
257 ccx.available_drop_glues().borrow_mut().insert(g, fn_nm);
258
259 let _s = StatRecorder::new(ccx, format!("drop {:?}", t));
260
261 let empty_substs = ccx.tcx().mk_substs(Substs::trans_empty());
262 let (arena, fcx): (TypedArena<_>, FunctionContext);
263 arena = TypedArena::new();
264 fcx = new_fn_ctxt(ccx, llfn, ast::DUMMY_NODE_ID, false,
265 ty::FnConverging(ccx.tcx().mk_nil()),
266 empty_substs, None, &arena);
267
268 let bcx = init_function(&fcx, false, ty::FnConverging(ccx.tcx().mk_nil()));
269
270 update_linkage(ccx, llfn, None, OriginalTranslation);
271
272 ccx.stats().n_glues_created.set(ccx.stats().n_glues_created.get() + 1);
273 // All glue functions take values passed *by alias*; this is a
274 // requirement since in many contexts glue is invoked indirectly and
275 // the caller has no idea if it's dealing with something that can be
276 // passed by value.
277 //
278 // llfn is expected be declared to take a parameter of the appropriate
279 // type, so we don't need to explicitly cast the function parameter.
280
281 let llrawptr0 = get_param(llfn, fcx.arg_offset() as c_uint);
282 let bcx = make_drop_glue(bcx, llrawptr0, g);
283 finish_fn(&fcx, bcx, ty::FnConverging(ccx.tcx().mk_nil()), DebugLoc::None);
284
285 llfn
286 }
287
288 fn trans_struct_drop_flag<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
289 t: Ty<'tcx>,
290 struct_data: ValueRef,
291 dtor_did: ast::DefId,
292 class_did: ast::DefId,
293 substs: &subst::Substs<'tcx>)
294 -> Block<'blk, 'tcx> {
295 assert!(type_is_sized(bcx.tcx(), t), "Precondition: caller must ensure t is sized");
296
297 let repr = adt::represent_type(bcx.ccx(), t);
298 let drop_flag = unpack_datum!(bcx, adt::trans_drop_flag_ptr(bcx, &*repr, struct_data));
299 let loaded = load_ty(bcx, drop_flag.val, bcx.tcx().dtor_type());
300 let drop_flag_llty = type_of(bcx.fcx.ccx, bcx.tcx().dtor_type());
301 let init_val = C_integral(drop_flag_llty, adt::DTOR_NEEDED as u64, false);
302
303 let bcx = if !bcx.ccx().check_drop_flag_for_sanity() {
304 bcx
305 } else {
306 let drop_flag_llty = type_of(bcx.fcx.ccx, bcx.tcx().dtor_type());
307 let done_val = C_integral(drop_flag_llty, adt::DTOR_DONE as u64, false);
308 let not_init = ICmp(bcx, llvm::IntNE, loaded, init_val, DebugLoc::None);
309 let not_done = ICmp(bcx, llvm::IntNE, loaded, done_val, DebugLoc::None);
310 let drop_flag_neither_initialized_nor_cleared =
311 And(bcx, not_init, not_done, DebugLoc::None);
312 with_cond(bcx, drop_flag_neither_initialized_nor_cleared, |cx| {
313 let llfn = cx.ccx().get_intrinsic(&("llvm.debugtrap"));
314 Call(cx, llfn, &[], None, DebugLoc::None);
315 cx
316 })
317 };
318
319 let drop_flag_dtor_needed = ICmp(bcx, llvm::IntEQ, loaded, init_val, DebugLoc::None);
320 with_cond(bcx, drop_flag_dtor_needed, |cx| {
321 trans_struct_drop(cx, t, struct_data, dtor_did, class_did, substs)
322 })
323 }
324
325 pub fn get_res_dtor<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
326 did: ast::DefId,
327 t: Ty<'tcx>,
328 parent_id: ast::DefId,
329 substs: &Substs<'tcx>)
330 -> ValueRef {
331 let _icx = push_ctxt("trans_res_dtor");
332 let did = inline::maybe_instantiate_inline(ccx, did);
333
334 if !substs.types.is_empty() {
335 assert_eq!(did.krate, ast::LOCAL_CRATE);
336
337 // Since we're in trans we don't care for any region parameters
338 let substs = ccx.tcx().mk_substs(Substs::erased(substs.types.clone()));
339
340 let (val, _, _) = monomorphize::monomorphic_fn(ccx, did, substs, None);
341
342 val
343 } else if did.krate == ast::LOCAL_CRATE {
344 get_item_val(ccx, did.node)
345 } else {
346 let tcx = ccx.tcx();
347 let name = csearch::get_symbol(&ccx.sess().cstore, did);
348 let class_ty = tcx.lookup_item_type(parent_id).ty.subst(tcx, substs);
349 let llty = type_of_dtor(ccx, class_ty);
350 let dtor_ty = ccx.tcx().mk_ctor_fn(did,
351 &[get_drop_glue_type(ccx, t)],
352 ccx.tcx().mk_nil());
353 foreign::get_extern_fn(ccx, &mut *ccx.externs().borrow_mut(), &name[..], llvm::CCallConv,
354 llty, dtor_ty)
355 }
356 }
357
358 fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
359 t: Ty<'tcx>,
360 v0: ValueRef,
361 dtor_did: ast::DefId,
362 class_did: ast::DefId,
363 substs: &subst::Substs<'tcx>)
364 -> Block<'blk, 'tcx>
365 {
366 debug!("trans_struct_drop t: {}", t);
367
368 // Find and call the actual destructor
369 let dtor_addr = get_res_dtor(bcx.ccx(), dtor_did, t, class_did, substs);
370
371 // Class dtors have no explicit args, so the params should
372 // just consist of the environment (self).
373 let params = unsafe {
374 let ty = Type::from_ref(llvm::LLVMTypeOf(dtor_addr));
375 ty.element_type().func_params()
376 };
377 assert_eq!(params.len(), if type_is_sized(bcx.tcx(), t) { 1 } else { 2 });
378
379 // Be sure to put the contents into a scope so we can use an invoke
380 // instruction to call the user destructor but still call the field
381 // destructors if the user destructor panics.
382 //
383 // FIXME (#14875) panic-in-drop semantics might be unsupported; we
384 // might well consider changing below to more direct code.
385 let contents_scope = bcx.fcx.push_custom_cleanup_scope();
386
387 // Issue #23611: schedule cleanup of contents, re-inspecting the
388 // discriminant (if any) in case of variant swap in drop code.
389 bcx.fcx.schedule_drop_adt_contents(cleanup::CustomScope(contents_scope), v0, t);
390
391 let glue_type = get_drop_glue_type(bcx.ccx(), t);
392 let dtor_ty = bcx.tcx().mk_ctor_fn(class_did, &[glue_type], bcx.tcx().mk_nil());
393 let (_, bcx) = if type_is_sized(bcx.tcx(), t) {
394 invoke(bcx, dtor_addr, &[v0], dtor_ty, DebugLoc::None)
395 } else {
396 let args = [Load(bcx, expr::get_dataptr(bcx, v0)), Load(bcx, expr::get_len(bcx, v0))];
397 invoke(bcx, dtor_addr, &args, dtor_ty, DebugLoc::None)
398 };
399
400 bcx.fcx.pop_and_trans_custom_cleanup_scope(bcx, contents_scope)
401 }
402
403 pub fn size_and_align_of_dst<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, t: Ty<'tcx>, info: ValueRef)
404 -> (ValueRef, ValueRef) {
405 debug!("calculate size of DST: {}; with lost info: {}",
406 t, bcx.val_to_string(info));
407 if type_is_sized(bcx.tcx(), t) {
408 let sizing_type = sizing_type_of(bcx.ccx(), t);
409 let size = C_uint(bcx.ccx(), llsize_of_alloc(bcx.ccx(), sizing_type));
410 let align = C_uint(bcx.ccx(), align_of(bcx.ccx(), t));
411 return (size, align);
412 }
413 match t.sty {
414 ty::TyStruct(id, substs) => {
415 let ccx = bcx.ccx();
416 // First get the size of all statically known fields.
417 // Don't use type_of::sizing_type_of because that expects t to be sized.
418 assert!(!t.is_simd(bcx.tcx()));
419 let repr = adt::represent_type(ccx, t);
420 let sizing_type = adt::sizing_type_of(ccx, &*repr, true);
421 let sized_size = C_uint(ccx, llsize_of_alloc(ccx, sizing_type));
422 let sized_align = C_uint(ccx, llalign_of_min(ccx, sizing_type));
423
424 // Recurse to get the size of the dynamically sized field (must be
425 // the last field).
426 let fields = bcx.tcx().struct_fields(id, substs);
427 let last_field = fields[fields.len()-1];
428 let field_ty = last_field.mt.ty;
429 let (unsized_size, unsized_align) = size_and_align_of_dst(bcx, field_ty, info);
430
431 // Return the sum of sizes and max of aligns.
432 let size = Add(bcx, sized_size, unsized_size, DebugLoc::None);
433 let align = Select(bcx,
434 ICmp(bcx,
435 llvm::IntULT,
436 sized_align,
437 unsized_align,
438 DebugLoc::None),
439 sized_align,
440 unsized_align);
441 (size, align)
442 }
443 ty::TyTrait(..) => {
444 // info points to the vtable and the second entry in the vtable is the
445 // dynamic size of the object.
446 let info = PointerCast(bcx, info, Type::int(bcx.ccx()).ptr_to());
447 let size_ptr = GEPi(bcx, info, &[1]);
448 let align_ptr = GEPi(bcx, info, &[2]);
449 (Load(bcx, size_ptr), Load(bcx, align_ptr))
450 }
451 ty::TySlice(_) | ty::TyStr => {
452 let unit_ty = t.sequence_element_type(bcx.tcx());
453 // The info in this case is the length of the str, so the size is that
454 // times the unit size.
455 let llunit_ty = sizing_type_of(bcx.ccx(), unit_ty);
456 let unit_align = llalign_of_min(bcx.ccx(), llunit_ty);
457 let unit_size = llsize_of_alloc(bcx.ccx(), llunit_ty);
458 (Mul(bcx, info, C_uint(bcx.ccx(), unit_size), DebugLoc::None),
459 C_uint(bcx.ccx(), unit_align))
460 }
461 _ => bcx.sess().bug(&format!("Unexpected unsized type, found {}", t))
462 }
463 }
464
465 fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueKind<'tcx>)
466 -> Block<'blk, 'tcx> {
467 let t = g.ty();
468 let skip_dtor = match g { DropGlueKind::Ty(_) => false, DropGlueKind::TyContents(_) => true };
469 // NB: v0 is an *alias* of type t here, not a direct value.
470 let _icx = push_ctxt("make_drop_glue");
471
472 // Only drop the value when it ... well, we used to check for
473 // non-null, (and maybe we need to continue doing so), but we now
474 // must definitely check for special bit-patterns corresponding to
475 // the special dtor markings.
476
477 let inttype = Type::int(bcx.ccx());
478 let dropped_pattern = C_integral(inttype, adt::dtor_done_usize(bcx.fcx.ccx) as u64, false);
479
480 match t.sty {
481 ty::TyBox(content_ty) => {
482 // Support for TyBox is built-in and its drop glue is
483 // special. It may move to library and have Drop impl. As
484 // a safe-guard, assert TyBox not used with TyContents.
485 assert!(!skip_dtor);
486 if !type_is_sized(bcx.tcx(), content_ty) {
487 let llval = GEPi(bcx, v0, &[0, abi::FAT_PTR_ADDR]);
488 let llbox = Load(bcx, llval);
489 let llbox_as_usize = PtrToInt(bcx, llbox, Type::int(bcx.ccx()));
490 let drop_flag_not_dropped_already =
491 ICmp(bcx, llvm::IntNE, llbox_as_usize, dropped_pattern, DebugLoc::None);
492 with_cond(bcx, drop_flag_not_dropped_already, |bcx| {
493 let bcx = drop_ty(bcx, v0, content_ty, DebugLoc::None);
494 let info = GEPi(bcx, v0, &[0, abi::FAT_PTR_EXTRA]);
495 let info = Load(bcx, info);
496 let (llsize, llalign) = size_and_align_of_dst(bcx, content_ty, info);
497
498 // `Box<ZeroSizeType>` does not allocate.
499 let needs_free = ICmp(bcx,
500 llvm::IntNE,
501 llsize,
502 C_uint(bcx.ccx(), 0u64),
503 DebugLoc::None);
504 with_cond(bcx, needs_free, |bcx| {
505 trans_exchange_free_dyn(bcx, llbox, llsize, llalign, DebugLoc::None)
506 })
507 })
508 } else {
509 let llval = v0;
510 let llbox = Load(bcx, llval);
511 let llbox_as_usize = PtrToInt(bcx, llbox, inttype);
512 let drop_flag_not_dropped_already =
513 ICmp(bcx, llvm::IntNE, llbox_as_usize, dropped_pattern, DebugLoc::None);
514 with_cond(bcx, drop_flag_not_dropped_already, |bcx| {
515 let bcx = drop_ty(bcx, llbox, content_ty, DebugLoc::None);
516 trans_exchange_free_ty(bcx, llbox, content_ty, DebugLoc::None)
517 })
518 }
519 }
520 ty::TyStruct(did, substs) | ty::TyEnum(did, substs) => {
521 let tcx = bcx.tcx();
522 match (tcx.ty_dtor(did), skip_dtor) {
523 (ty::TraitDtor(dtor, true), false) => {
524 // FIXME(16758) Since the struct is unsized, it is hard to
525 // find the drop flag (which is at the end of the struct).
526 // Lets just ignore the flag and pretend everything will be
527 // OK.
528 if type_is_sized(bcx.tcx(), t) {
529 trans_struct_drop_flag(bcx, t, v0, dtor, did, substs)
530 } else {
531 // Give the user a heads up that we are doing something
532 // stupid and dangerous.
533 bcx.sess().warn(&format!("Ignoring drop flag in destructor for {}\
534 because the struct is unsized. See issue\
535 #16758", t));
536 trans_struct_drop(bcx, t, v0, dtor, did, substs)
537 }
538 }
539 (ty::TraitDtor(dtor, false), false) => {
540 trans_struct_drop(bcx, t, v0, dtor, did, substs)
541 }
542 (ty::NoDtor, _) | (_, true) => {
543 // No dtor? Just the default case
544 iter_structural_ty(bcx, v0, t, |bb, vv, tt| drop_ty(bb, vv, tt, DebugLoc::None))
545 }
546 }
547 }
548 ty::TyTrait(..) => {
549 // No support in vtable for distinguishing destroying with
550 // versus without calling Drop::drop. Assert caller is
551 // okay with always calling the Drop impl, if any.
552 assert!(!skip_dtor);
553 let data_ptr = GEPi(bcx, v0, &[0, abi::FAT_PTR_ADDR]);
554 let vtable_ptr = Load(bcx, GEPi(bcx, v0, &[0, abi::FAT_PTR_EXTRA]));
555 let dtor = Load(bcx, vtable_ptr);
556 Call(bcx,
557 dtor,
558 &[PointerCast(bcx, Load(bcx, data_ptr), Type::i8p(bcx.ccx()))],
559 None,
560 DebugLoc::None);
561 bcx
562 }
563 _ => {
564 if bcx.fcx.type_needs_drop(t) {
565 iter_structural_ty(bcx,
566 v0,
567 t,
568 |bb, vv, tt| drop_ty(bb, vv, tt, DebugLoc::None))
569 } else {
570 bcx
571 }
572 }
573 }
574 }