]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/trans/glue.rs
Correctly generate drop glue for `Box<str>`
[rust.git] / src / librustc / middle / 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 taking, dropping, etc as well as type descriptors.
14
15
16 use back::abi;
17 use back::link::*;
18 use llvm::{ValueRef, True, get_param};
19 use llvm;
20 use middle::lang_items::ExchangeFreeFnLangItem;
21 use middle::subst;
22 use middle::subst::Subst;
23 use middle::trans::adt;
24 use middle::trans::base::*;
25 use middle::trans::build::*;
26 use middle::trans::callee;
27 use middle::trans::cleanup;
28 use middle::trans::cleanup::CleanupMethods;
29 use middle::trans::common::*;
30 use middle::trans::datum;
31 use middle::trans::debuginfo;
32 use middle::trans::expr;
33 use middle::trans::machine::*;
34 use middle::trans::reflect;
35 use middle::trans::tvec;
36 use middle::trans::type_::Type;
37 use middle::trans::type_of::{type_of, sizing_type_of, align_of};
38 use middle::ty;
39 use util::ppaux::{ty_to_short_str, Repr};
40 use util::ppaux;
41
42 use arena::TypedArena;
43 use std::c_str::ToCStr;
44 use std::cell::Cell;
45 use libc::c_uint;
46 use syntax::ast;
47 use syntax::parse::token;
48
49 pub fn trans_exchange_free_dyn<'blk, 'tcx>(cx: Block<'blk, 'tcx>, v: ValueRef,
50                                            size: ValueRef, align: ValueRef)
51                                            -> Block<'blk, 'tcx> {
52     let _icx = push_ctxt("trans_exchange_free");
53     let ccx = cx.ccx();
54     callee::trans_lang_call(cx,
55         langcall(cx, None, "", ExchangeFreeFnLangItem),
56         [PointerCast(cx, v, Type::i8p(ccx)), size, align],
57         Some(expr::Ignore)).bcx
58 }
59
60 pub fn trans_exchange_free<'blk, 'tcx>(cx: Block<'blk, 'tcx>, v: ValueRef,
61                                        size: u64, align: u64) -> Block<'blk, 'tcx> {
62     trans_exchange_free_dyn(cx, v, C_uint(cx.ccx(), size as uint),
63                             C_uint(cx.ccx(), align as uint))
64 }
65
66 pub fn trans_exchange_free_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, ptr: ValueRef,
67                                           content_ty: ty::t) -> Block<'blk, 'tcx> {
68     assert!(ty::type_is_sized(bcx.ccx().tcx(), content_ty));
69     let sizing_type = sizing_type_of(bcx.ccx(), content_ty);
70     let content_size = llsize_of_alloc(bcx.ccx(), sizing_type);
71
72     // `Box<ZeroSizeType>` does not allocate.
73     if content_size != 0 {
74         let content_align = align_of(bcx.ccx(), content_ty);
75         trans_exchange_free(bcx, ptr, content_size, content_align)
76     } else {
77         bcx
78     }
79 }
80
81 pub fn get_drop_glue_type(ccx: &CrateContext, t: ty::t) -> ty::t {
82     let tcx = ccx.tcx();
83     // Even if there is no dtor for t, there might be one deeper down and we
84     // might need to pass in the vtable ptr.
85     if !ty::type_is_sized(tcx, t) {
86         return t
87     }
88     if !ty::type_needs_drop(tcx, t) {
89         return ty::mk_i8();
90     }
91     match ty::get(t).sty {
92         ty::ty_uniq(typ) if !ty::type_needs_drop(tcx, typ)
93                          && ty::type_is_sized(tcx, typ) => {
94             let llty = sizing_type_of(ccx, typ);
95             // `Box<ZeroSizeType>` does not allocate.
96             if llsize_of_alloc(ccx, llty) == 0 {
97                 ty::mk_i8()
98             } else {
99                 t
100             }
101         }
102         _ => t
103     }
104 }
105
106 pub fn drop_ty<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
107                            v: ValueRef,
108                            t: ty::t,
109                            source_location: Option<NodeInfo>)
110                            -> Block<'blk, 'tcx> {
111     // NB: v is an *alias* of type t here, not a direct value.
112     debug!("drop_ty(t={})", t.repr(bcx.tcx()));
113     let _icx = push_ctxt("drop_ty");
114     if ty::type_needs_drop(bcx.tcx(), t) {
115         let ccx = bcx.ccx();
116         let glue = get_drop_glue(ccx, t);
117         let glue_type = get_drop_glue_type(ccx, t);
118         let ptr = if glue_type != t {
119             PointerCast(bcx, v, type_of(ccx, glue_type).ptr_to())
120         } else {
121             v
122         };
123
124         match source_location {
125             Some(sl) => debuginfo::set_source_location(bcx.fcx, sl.id, sl.span),
126             None => debuginfo::clear_source_location(bcx.fcx)
127         };
128
129         Call(bcx, glue, [ptr], None);
130     }
131     bcx
132 }
133
134 pub fn drop_ty_immediate<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
135                                      v: ValueRef,
136                                      t: ty::t,
137                                      source_location: Option<NodeInfo>)
138                                      -> Block<'blk, 'tcx> {
139     let _icx = push_ctxt("drop_ty_immediate");
140     let vp = alloca(bcx, type_of(bcx.ccx(), t), "");
141     Store(bcx, v, vp);
142     drop_ty(bcx, vp, t, source_location)
143 }
144
145 pub fn get_drop_glue(ccx: &CrateContext, t: ty::t) -> ValueRef {
146     debug!("make drop glue for {}", ppaux::ty_to_string(ccx.tcx(), t));
147     let t = get_drop_glue_type(ccx, t);
148     debug!("drop glue type {}", ppaux::ty_to_string(ccx.tcx(), t));
149     match ccx.drop_glues().borrow().find(&t) {
150         Some(&glue) => return glue,
151         _ => { }
152     }
153
154     let llty = if ty::type_is_sized(ccx.tcx(), t) {
155         type_of(ccx, t).ptr_to()
156     } else {
157         type_of(ccx, ty::mk_uniq(ccx.tcx(), t)).ptr_to()
158     };
159
160     let llfnty = Type::glue_fn(ccx, llty);
161
162     let (glue, new_sym) = match ccx.available_drop_glues().borrow().find(&t) {
163         Some(old_sym) => {
164             let glue = decl_cdecl_fn(ccx, old_sym.as_slice(), llfnty, ty::mk_nil());
165             (glue, None)
166         },
167         None => {
168             let (sym, glue) = declare_generic_glue(ccx, t, llfnty, "drop");
169             (glue, Some(sym))
170         },
171     };
172
173     ccx.drop_glues().borrow_mut().insert(t, glue);
174
175     // To avoid infinite recursion, don't `make_drop_glue` until after we've
176     // added the entry to the `drop_glues` cache.
177     match new_sym {
178         Some(sym) => {
179             ccx.available_drop_glues().borrow_mut().insert(t, sym);
180             // We're creating a new drop glue, so also generate a body.
181             make_generic_glue(ccx, t, glue, make_drop_glue, "drop");
182         },
183         None => {},
184     }
185
186     glue
187 }
188
189 pub fn lazily_emit_visit_glue(ccx: &CrateContext, ti: &tydesc_info) -> ValueRef {
190     let _icx = push_ctxt("lazily_emit_visit_glue");
191
192     let llfnty = Type::glue_fn(ccx, type_of(ccx, ti.ty).ptr_to());
193
194     match ti.visit_glue.get() {
195         Some(visit_glue) => visit_glue,
196         None => {
197             debug!("+++ lazily_emit_tydesc_glue VISIT {}", ppaux::ty_to_string(ccx.tcx(), ti.ty));
198
199             let (glue_fn, new_sym) = match ccx.available_visit_glues().borrow().find(&ti.ty) {
200                 Some(old_sym) => {
201                     let glue_fn = decl_cdecl_fn(ccx, old_sym.as_slice(), llfnty, ty::mk_nil());
202                     (glue_fn, None)
203                 },
204                 None => {
205                     let (sym, glue_fn) = declare_generic_glue(ccx, ti.ty, llfnty, "visit");
206                     (glue_fn, Some(sym))
207                 },
208             };
209
210             ti.visit_glue.set(Some(glue_fn));
211
212             match new_sym {
213                 Some(sym) => {
214                     ccx.available_visit_glues().borrow_mut().insert(ti.ty, sym);
215                     make_generic_glue(ccx, ti.ty, glue_fn, make_visit_glue, "visit");
216                 },
217                 None => {},
218             }
219
220             debug!("--- lazily_emit_tydesc_glue VISIT {}", ppaux::ty_to_string(ccx.tcx(), ti.ty));
221             glue_fn
222         }
223     }
224 }
225
226 // See [Note-arg-mode]
227 pub fn call_visit_glue(bcx: Block, v: ValueRef, tydesc: ValueRef) {
228     let _icx = push_ctxt("call_visit_glue");
229
230     // Select the glue function to call from the tydesc
231     let llfn = Load(bcx, GEPi(bcx, tydesc, [0u, abi::tydesc_field_visit_glue]));
232     let llrawptr = PointerCast(bcx, v, Type::i8p(bcx.ccx()));
233
234     Call(bcx, llfn, [llrawptr], None);
235 }
236
237 fn make_visit_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v: ValueRef, t: ty::t)
238                                -> Block<'blk, 'tcx> {
239     let _icx = push_ctxt("make_visit_glue");
240     let mut bcx = bcx;
241     let (visitor_trait, object_ty) = match ty::visitor_object_ty(bcx.tcx(),
242                                                                  ty::ReStatic,
243                                                                  ty::ReStatic) {
244         Ok(pair) => pair,
245         Err(s) => {
246             bcx.tcx().sess.fatal(s.as_slice());
247         }
248     };
249     let v = PointerCast(bcx, v, type_of(bcx.ccx(), object_ty).ptr_to());
250     bcx = reflect::emit_calls_to_trait_visit_ty(bcx, t, v, visitor_trait.def_id);
251     bcx
252 }
253
254 fn trans_struct_drop_flag<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
255                                       t: ty::t,
256                                       v0: ValueRef,
257                                       dtor_did: ast::DefId,
258                                       class_did: ast::DefId,
259                                       substs: &subst::Substs)
260                                       -> Block<'blk, 'tcx> {
261     let repr = adt::represent_type(bcx.ccx(), t);
262     let struct_data = if ty::type_is_sized(bcx.tcx(), t) {
263         v0
264     } else {
265         let llval = GEPi(bcx, v0, [0, abi::slice_elt_base]);
266         Load(bcx, llval)
267     };
268     let drop_flag = unpack_datum!(bcx, adt::trans_drop_flag_ptr(bcx, &*repr, struct_data));
269     with_cond(bcx, load_ty(bcx, drop_flag.val, ty::mk_bool()), |cx| {
270         trans_struct_drop(cx, t, v0, dtor_did, class_did, substs)
271     })
272 }
273
274 fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
275                                  t: ty::t,
276                                  v0: ValueRef,
277                                  dtor_did: ast::DefId,
278                                  class_did: ast::DefId,
279                                  substs: &subst::Substs)
280                                  -> Block<'blk, 'tcx> {
281     let repr = adt::represent_type(bcx.ccx(), t);
282
283     // Find and call the actual destructor
284     let dtor_addr = get_res_dtor(bcx.ccx(), dtor_did, t,
285                                  class_did, substs);
286
287     // The first argument is the "self" argument for drop
288     let params = unsafe {
289         let ty = Type::from_ref(llvm::LLVMTypeOf(dtor_addr));
290         ty.element_type().func_params()
291     };
292
293     let fty = ty::lookup_item_type(bcx.tcx(), dtor_did).ty.subst(bcx.tcx(), substs);
294     let self_ty = match ty::get(fty).sty {
295         ty::ty_bare_fn(ref f) => {
296             assert!(f.sig.inputs.len() == 1);
297             f.sig.inputs[0]
298         }
299         _ => bcx.sess().bug(format!("Expected function type, found {}",
300                                     bcx.ty_to_string(fty)).as_slice())
301     };
302
303     let (struct_data, info) = if ty::type_is_sized(bcx.tcx(), t) {
304         (v0, None)
305     } else {
306         let data = GEPi(bcx, v0, [0, abi::slice_elt_base]);
307         let info = GEPi(bcx, v0, [0, abi::slice_elt_len]);
308         (Load(bcx, data), Some(Load(bcx, info)))
309     };
310
311     adt::fold_variants(bcx, &*repr, struct_data, |variant_cx, st, value| {
312         // Be sure to put all of the fields into a scope so we can use an invoke
313         // instruction to call the user destructor but still call the field
314         // destructors if the user destructor fails.
315         let field_scope = variant_cx.fcx.push_custom_cleanup_scope();
316
317         // Class dtors have no explicit args, so the params should
318         // just consist of the environment (self).
319         assert_eq!(params.len(), 1);
320         let self_arg = if ty::type_is_fat_ptr(bcx.tcx(), self_ty) {
321             // The dtor expects a fat pointer, so make one, even if we have to fake it.
322             let boxed_ty = ty::mk_open(bcx.tcx(), t);
323             let scratch = datum::rvalue_scratch_datum(bcx, boxed_ty, "__fat_ptr_drop_self");
324             Store(bcx, value, GEPi(bcx, scratch.val, [0, abi::slice_elt_base]));
325             Store(bcx,
326                   // If we just had a thin pointer, make a fat pointer by sticking
327                   // null where we put the unsizing info. This works because t
328                   // is a sized type, so we will only unpack the fat pointer, never
329                   // use the fake info.
330                   info.unwrap_or(C_null(Type::i8p(bcx.ccx()))),
331                   GEPi(bcx, scratch.val, [0, abi::slice_elt_len]));
332             PointerCast(variant_cx, scratch.val, *params.get(0))
333         } else {
334             PointerCast(variant_cx, value, *params.get(0))
335         };
336         let args = vec!(self_arg);
337
338         // Add all the fields as a value which needs to be cleaned at the end of
339         // this scope. Iterate in reverse order so a Drop impl doesn't reverse
340         // the order in which fields get dropped.
341         for (i, ty) in st.fields.iter().enumerate().rev() {
342             let llfld_a = adt::struct_field_ptr(variant_cx, &*st, value, i, false);
343
344             let val = if ty::type_is_sized(bcx.tcx(), *ty) {
345                 llfld_a
346             } else {
347                 let boxed_ty = ty::mk_open(bcx.tcx(), *ty);
348                 let scratch = datum::rvalue_scratch_datum(bcx, boxed_ty, "__fat_ptr_drop_field");
349                 Store(bcx, llfld_a, GEPi(bcx, scratch.val, [0, abi::slice_elt_base]));
350                 Store(bcx, info.unwrap(), GEPi(bcx, scratch.val, [0, abi::slice_elt_len]));
351                 scratch.val
352             };
353             variant_cx.fcx.schedule_drop_mem(cleanup::CustomScope(field_scope),
354                                              val, *ty);
355         }
356
357         let dtor_ty = ty::mk_ctor_fn(variant_cx.tcx(), ast::DUMMY_NODE_ID,
358                                      [get_drop_glue_type(bcx.ccx(), t)], ty::mk_nil());
359         let (_, variant_cx) = invoke(variant_cx, dtor_addr, args, dtor_ty, None, false);
360
361         variant_cx.fcx.pop_and_trans_custom_cleanup_scope(variant_cx, field_scope);
362         variant_cx
363     })
364 }
365
366 fn size_and_align_of_dst(bcx: Block, t :ty::t, info: ValueRef) -> (ValueRef, ValueRef) {
367     debug!("calculate size of DST: {}; with lost info: {}",
368            bcx.ty_to_string(t), bcx.val_to_string(info));
369     if ty::type_is_sized(bcx.tcx(), t) {
370         let sizing_type = sizing_type_of(bcx.ccx(), t);
371         let size = C_uint(bcx.ccx(), llsize_of_alloc(bcx.ccx(), sizing_type) as uint);
372         let align = C_uint(bcx.ccx(), align_of(bcx.ccx(), t) as uint);
373         return (size, align);
374     }
375     match ty::get(t).sty {
376         ty::ty_struct(id, ref substs) => {
377             let ccx = bcx.ccx();
378             // First get the size of all statically known fields.
379             // Don't use type_of::sizing_type_of because that expects t to be sized.
380             assert!(!ty::type_is_simd(bcx.tcx(), t));
381             let repr = adt::represent_type(ccx, t);
382             let sizing_type = adt::sizing_type_of(ccx, &*repr, true);
383             let sized_size = C_uint(ccx, llsize_of_alloc(ccx, sizing_type) as uint);
384             let sized_align = C_uint(ccx, llalign_of_min(ccx, sizing_type) as uint);
385
386             // Recurse to get the size of the dynamically sized field (must be
387             // the last field).
388             let fields = ty::struct_fields(bcx.tcx(), id, substs);
389             let last_field = fields[fields.len()-1];
390             let field_ty = last_field.mt.ty;
391             let (unsized_size, unsized_align) = size_and_align_of_dst(bcx, field_ty, info);
392
393             // Return the sum of sizes and max of aligns.
394             let size = Add(bcx, sized_size, unsized_size);
395             let align = Select(bcx,
396                                ICmp(bcx, llvm::IntULT, sized_align, unsized_align),
397                                sized_align,
398                                unsized_align);
399             (size, align)
400         }
401         ty::ty_trait(..) => {
402             // info points to the vtable and the second entry in the vtable is the
403             // dynamic size of the object.
404             let info = PointerCast(bcx, info, Type::int(bcx.ccx()).ptr_to());
405             let size_ptr = GEPi(bcx, info, [1u]);
406             let align_ptr = GEPi(bcx, info, [2u]);
407             (Load(bcx, size_ptr), Load(bcx, align_ptr))
408         }
409         ty::ty_vec(unit_ty, None) => {
410             // The info in this case is the length of the vec, so the size is that
411             // times the unit size.
412             let llunit_ty = sizing_type_of(bcx.ccx(), unit_ty);
413             let unit_size = llsize_of_alloc(bcx.ccx(), llunit_ty);
414             (Mul(bcx, info, C_uint(bcx.ccx(), unit_size as uint)), C_uint(bcx.ccx(), 8))
415         }
416         _ => bcx.sess().bug(format!("Unexpected unsized type, found {}",
417                                     bcx.ty_to_string(t)).as_slice())
418     }
419 }
420
421 fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, t: ty::t)
422                               -> Block<'blk, 'tcx> {
423     // NB: v0 is an *alias* of type t here, not a direct value.
424     let _icx = push_ctxt("make_drop_glue");
425     match ty::get(t).sty {
426         ty::ty_uniq(content_ty) => {
427             match ty::get(content_ty).sty {
428                 ty::ty_vec(ty, None) => {
429                     tvec::make_drop_glue_unboxed(bcx, v0, ty, true)
430                 }
431                 ty::ty_str => {
432                     let unit_ty = ty::sequence_element_type(bcx.tcx(), content_ty);
433                     tvec::make_drop_glue_unboxed(bcx, v0, unit_ty, true)
434                 }
435                 ty::ty_trait(..) => {
436                     let lluniquevalue = GEPi(bcx, v0, [0, abi::trt_field_box]);
437                     // Only drop the value when it is non-null
438                     let concrete_ptr = Load(bcx, lluniquevalue);
439                     with_cond(bcx, IsNotNull(bcx, concrete_ptr), |bcx| {
440                         let dtor_ptr = Load(bcx, GEPi(bcx, v0, [0, abi::trt_field_vtable]));
441                         let dtor = Load(bcx, dtor_ptr);
442                         Call(bcx,
443                              dtor,
444                              [PointerCast(bcx, lluniquevalue, Type::i8p(bcx.ccx()))],
445                              None);
446                         bcx
447                     })
448                 }
449                 ty::ty_struct(..) if !ty::type_is_sized(bcx.tcx(), content_ty) => {
450                     let llval = GEPi(bcx, v0, [0, abi::slice_elt_base]);
451                     let llbox = Load(bcx, llval);
452                     let not_null = IsNotNull(bcx, llbox);
453                     with_cond(bcx, not_null, |bcx| {
454                         let bcx = drop_ty(bcx, v0, content_ty, None);
455                         let info = GEPi(bcx, v0, [0, abi::slice_elt_len]);
456                         let info = Load(bcx, info);
457                         let (llsize, llalign) = size_and_align_of_dst(bcx, content_ty, info);
458                         trans_exchange_free_dyn(bcx, llbox, llsize, llalign)
459                     })
460                 }
461                 _ => {
462                     assert!(ty::type_is_sized(bcx.tcx(), content_ty));
463                     let llval = v0;
464                     let llbox = Load(bcx, llval);
465                     let not_null = IsNotNull(bcx, llbox);
466                     with_cond(bcx, not_null, |bcx| {
467                         let bcx = drop_ty(bcx, llbox, content_ty, None);
468                         trans_exchange_free_ty(bcx, llbox, content_ty)
469                     })
470                 }
471             }
472         }
473         ty::ty_struct(did, ref substs) | ty::ty_enum(did, ref substs) => {
474             let tcx = bcx.tcx();
475             match ty::ty_dtor(tcx, did) {
476                 ty::TraitDtor(dtor, true) => {
477                     // FIXME(16758) Since the struct is unsized, it is hard to
478                     // find the drop flag (which is at the end of the struct).
479                     // Lets just ignore the flag and pretend everything will be
480                     // OK.
481                     if ty::type_is_sized(bcx.tcx(), t) {
482                         trans_struct_drop_flag(bcx, t, v0, dtor, did, substs)
483                     } else {
484                         // Give the user a heads up that we are doing something
485                         // stupid and dangerous.
486                         bcx.sess().warn(format!("Ignoring drop flag in destructor for {}\
487                                                  because the struct is unsized. See issue\
488                                                  #16758",
489                                                 bcx.ty_to_string(t)).as_slice());
490                         trans_struct_drop(bcx, t, v0, dtor, did, substs)
491                     }
492                 }
493                 ty::TraitDtor(dtor, false) => {
494                     trans_struct_drop(bcx, t, v0, dtor, did, substs)
495                 }
496                 ty::NoDtor => {
497                     // No dtor? Just the default case
498                     iter_structural_ty(bcx, v0, t, |bb, vv, tt| drop_ty(bb, vv, tt, None))
499                 }
500             }
501         }
502         ty::ty_unboxed_closure(..) => iter_structural_ty(bcx,
503                                                          v0,
504                                                          t,
505                                                          |bb, vv, tt| drop_ty(bb, vv, tt, None)),
506         ty::ty_closure(ref f) if f.store == ty::UniqTraitStore => {
507             let box_cell_v = GEPi(bcx, v0, [0u, abi::fn_field_box]);
508             let env = Load(bcx, box_cell_v);
509             let env_ptr_ty = Type::at_box(bcx.ccx(), Type::i8(bcx.ccx())).ptr_to();
510             let env = PointerCast(bcx, env, env_ptr_ty);
511             with_cond(bcx, IsNotNull(bcx, env), |bcx| {
512                 let dtor_ptr = GEPi(bcx, env, [0u, abi::box_field_drop_glue]);
513                 let dtor = Load(bcx, dtor_ptr);
514                 Call(bcx, dtor, [PointerCast(bcx, box_cell_v, Type::i8p(bcx.ccx()))], None);
515                 bcx
516             })
517         }
518         ty::ty_trait(..) => {
519             // No need to do a null check here (as opposed to the Box<trait case
520             // above), because this happens for a trait field in an unsized
521             // struct. If anything is null, it is the whole struct and we won't
522             // get here.
523             let lluniquevalue = GEPi(bcx, v0, [0, abi::trt_field_box]);
524             let dtor_ptr = Load(bcx, GEPi(bcx, v0, [0, abi::trt_field_vtable]));
525             let dtor = Load(bcx, dtor_ptr);
526             Call(bcx,
527                  dtor,
528                  [PointerCast(bcx, Load(bcx, lluniquevalue), Type::i8p(bcx.ccx()))],
529                  None);
530             bcx
531         }
532         ty::ty_vec(ty, None) => tvec::make_drop_glue_unboxed(bcx, v0, ty, false),
533         _ => {
534             assert!(ty::type_is_sized(bcx.tcx(), t));
535             if ty::type_needs_drop(bcx.tcx(), t) &&
536                 ty::type_is_structural(t) {
537                 iter_structural_ty(bcx, v0, t, |bb, vv, tt| drop_ty(bb, vv, tt, None))
538             } else {
539                 bcx
540             }
541         }
542     }
543 }
544
545 // Generates the declaration for (but doesn't emit) a type descriptor.
546 pub fn declare_tydesc(ccx: &CrateContext, t: ty::t) -> tydesc_info {
547     // If emit_tydescs already ran, then we shouldn't be creating any new
548     // tydescs.
549     assert!(!ccx.finished_tydescs().get());
550
551     let llty = type_of(ccx, t);
552
553     if ccx.sess().count_type_sizes() {
554         println!("{}\t{}", llsize_of_real(ccx, llty),
555                  ppaux::ty_to_string(ccx.tcx(), t));
556     }
557
558     let llsize = llsize_of(ccx, llty);
559     let llalign = llalign_of(ccx, llty);
560     let name = mangle_internal_name_by_type_and_seq(ccx, t, "tydesc");
561     debug!("+++ declare_tydesc {} {}", ppaux::ty_to_string(ccx.tcx(), t), name);
562     let gvar = name.as_slice().with_c_str(|buf| {
563         unsafe {
564             llvm::LLVMAddGlobal(ccx.llmod(), ccx.tydesc_type().to_ref(), buf)
565         }
566     });
567     note_unique_llvm_symbol(ccx, name);
568
569     let ty_name = token::intern_and_get_ident(
570         ppaux::ty_to_string(ccx.tcx(), t).as_slice());
571     let ty_name = C_str_slice(ccx, ty_name);
572
573     debug!("--- declare_tydesc {}", ppaux::ty_to_string(ccx.tcx(), t));
574     tydesc_info {
575         ty: t,
576         tydesc: gvar,
577         size: llsize,
578         align: llalign,
579         name: ty_name,
580         visit_glue: Cell::new(None),
581     }
582 }
583
584 fn declare_generic_glue(ccx: &CrateContext, t: ty::t, llfnty: Type,
585                         name: &str) -> (String, ValueRef) {
586     let _icx = push_ctxt("declare_generic_glue");
587     let fn_nm = mangle_internal_name_by_type_and_seq(
588         ccx,
589         t,
590         format!("glue_{}", name).as_slice());
591     let llfn = decl_cdecl_fn(ccx, fn_nm.as_slice(), llfnty, ty::mk_nil());
592     note_unique_llvm_symbol(ccx, fn_nm.clone());
593     return (fn_nm, llfn);
594 }
595
596 fn make_generic_glue(ccx: &CrateContext,
597                      t: ty::t,
598                      llfn: ValueRef,
599                      helper: <'blk, 'tcx> |Block<'blk, 'tcx>, ValueRef, ty::t|
600                                            -> Block<'blk, 'tcx>,
601                      name: &str)
602                      -> ValueRef {
603     let _icx = push_ctxt("make_generic_glue");
604     let glue_name = format!("glue {} {}", name, ty_to_short_str(ccx.tcx(), t));
605     let _s = StatRecorder::new(ccx, glue_name);
606
607     let arena = TypedArena::new();
608     let empty_param_substs = param_substs::empty();
609     let fcx = new_fn_ctxt(ccx, llfn, ast::DUMMY_NODE_ID, false, ty::mk_nil(),
610                           &empty_param_substs, None, &arena);
611
612     let bcx = init_function(&fcx, false, ty::mk_nil());
613
614     update_linkage(ccx, llfn, None, OriginalTranslation);
615
616     ccx.stats().n_glues_created.set(ccx.stats().n_glues_created.get() + 1u);
617     // All glue functions take values passed *by alias*; this is a
618     // requirement since in many contexts glue is invoked indirectly and
619     // the caller has no idea if it's dealing with something that can be
620     // passed by value.
621     //
622     // llfn is expected be declared to take a parameter of the appropriate
623     // type, so we don't need to explicitly cast the function parameter.
624
625     let llrawptr0 = get_param(llfn, fcx.arg_pos(0) as c_uint);
626     let bcx = helper(bcx, llrawptr0, t);
627     finish_fn(&fcx, bcx, ty::mk_nil());
628
629     llfn
630 }
631
632 pub fn emit_tydescs(ccx: &CrateContext) {
633     let _icx = push_ctxt("emit_tydescs");
634     // As of this point, allow no more tydescs to be created.
635     ccx.finished_tydescs().set(true);
636     let glue_fn_ty = Type::generic_glue_fn(ccx).ptr_to();
637     for (_, ti) in ccx.tydescs().borrow().iter() {
638         // Each of the glue functions needs to be cast to a generic type
639         // before being put into the tydesc because we only have a singleton
640         // tydesc type. Then we'll recast each function to its real type when
641         // calling it.
642         let drop_glue = unsafe {
643             llvm::LLVMConstPointerCast(get_drop_glue(ccx, ti.ty), glue_fn_ty.to_ref())
644         };
645         ccx.stats().n_real_glues.set(ccx.stats().n_real_glues.get() + 1);
646         let visit_glue =
647             match ti.visit_glue.get() {
648               None => {
649                   ccx.stats().n_null_glues.set(ccx.stats().n_null_glues.get() +
650                                              1u);
651                   C_null(glue_fn_ty)
652               }
653               Some(v) => {
654                 unsafe {
655                     ccx.stats().n_real_glues.set(ccx.stats().n_real_glues.get() +
656                                                1);
657                     llvm::LLVMConstPointerCast(v, glue_fn_ty.to_ref())
658                 }
659               }
660             };
661
662         let tydesc = C_named_struct(ccx.tydesc_type(),
663                                     [ti.size, // size
664                                      ti.align, // align
665                                      drop_glue, // drop_glue
666                                      visit_glue, // visit_glue
667                                      ti.name]); // name
668
669         unsafe {
670             let gvar = ti.tydesc;
671             llvm::LLVMSetInitializer(gvar, tydesc);
672             llvm::LLVMSetGlobalConstant(gvar, True);
673             llvm::SetLinkage(gvar, llvm::InternalLinkage);
674         }
675     };
676 }