]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
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 | #![allow(non_camel_case_types)] | |
12 | ||
1a4d82fc JJ |
13 | use middle::subst; |
14 | use trans::adt; | |
15 | use trans::common::*; | |
16 | use trans::foreign; | |
17 | use trans::machine; | |
18 | use middle::ty::{self, RegionEscape, Ty}; | |
1a4d82fc JJ |
19 | |
20 | use trans::type_::Type; | |
21 | ||
1a4d82fc JJ |
22 | use syntax::abi; |
23 | use syntax::ast; | |
24 | ||
25 | // LLVM doesn't like objects that are too big. Issue #17913 | |
26 | fn ensure_array_fits_in_address_space<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, | |
27 | llet: Type, | |
28 | size: machine::llsize, | |
29 | scapegoat: Ty<'tcx>) { | |
30 | let esz = machine::llsize_of_alloc(ccx, llet); | |
31 | match esz.checked_mul(size) { | |
32 | Some(n) if n < ccx.obj_size_bound() => {} | |
33 | _ => { ccx.report_overbig_object(scapegoat) } | |
34 | } | |
35 | } | |
36 | ||
37 | pub fn arg_is_indirect<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, | |
38 | arg_ty: Ty<'tcx>) -> bool { | |
62682a34 | 39 | !type_is_immediate(ccx, arg_ty) && !type_is_fat_ptr(ccx.tcx(), arg_ty) |
1a4d82fc JJ |
40 | } |
41 | ||
42 | pub fn return_uses_outptr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, | |
43 | ty: Ty<'tcx>) -> bool { | |
62682a34 | 44 | arg_is_indirect(ccx, ty) |
1a4d82fc JJ |
45 | } |
46 | ||
47 | pub fn type_of_explicit_arg<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, | |
48 | arg_ty: Ty<'tcx>) -> Type { | |
49 | let llty = arg_type_of(ccx, arg_ty); | |
50 | if arg_is_indirect(ccx, arg_ty) { | |
51 | llty.ptr_to() | |
52 | } else { | |
53 | llty | |
54 | } | |
55 | } | |
56 | ||
c1a9b12d SL |
57 | /// Yields the types of the "real" arguments for a function using the `RustCall` |
58 | /// ABI by untupling the arguments of the function. | |
59 | pub fn untuple_arguments<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, | |
60 | inputs: &[Ty<'tcx>]) | |
61 | -> Vec<Ty<'tcx>> { | |
9346a6ac | 62 | if inputs.is_empty() { |
1a4d82fc JJ |
63 | return Vec::new() |
64 | } | |
65 | ||
66 | let mut result = Vec::new(); | |
67 | for (i, &arg_prior_to_tuple) in inputs.iter().enumerate() { | |
68 | if i < inputs.len() - 1 { | |
69 | result.push(arg_prior_to_tuple); | |
70 | } | |
71 | } | |
72 | ||
73 | match inputs[inputs.len() - 1].sty { | |
62682a34 | 74 | ty::TyTuple(ref tupled_arguments) => { |
c1a9b12d | 75 | debug!("untuple_arguments(): untupling arguments"); |
85aaf69f | 76 | for &tupled_argument in tupled_arguments { |
1a4d82fc JJ |
77 | result.push(tupled_argument); |
78 | } | |
79 | } | |
80 | _ => { | |
81 | ccx.tcx().sess.bug("argument to function with \"rust-call\" ABI \ | |
82 | is neither a tuple nor unit") | |
83 | } | |
84 | } | |
85 | ||
86 | result | |
87 | } | |
88 | ||
89 | pub fn type_of_rust_fn<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, | |
90 | llenvironment_type: Option<Type>, | |
91 | sig: &ty::Binder<ty::FnSig<'tcx>>, | |
92 | abi: abi::Abi) | |
93 | -> Type | |
94 | { | |
62682a34 SL |
95 | debug!("type_of_rust_fn(sig={:?},abi={:?})", |
96 | sig, | |
85aaf69f SL |
97 | abi); |
98 | ||
c1a9b12d | 99 | let sig = cx.tcx().erase_late_bound_regions(sig); |
1a4d82fc JJ |
100 | assert!(!sig.variadic); // rust fns are never variadic |
101 | ||
102 | let mut atys: Vec<Type> = Vec::new(); | |
103 | ||
104 | // First, munge the inputs, if this has the `rust-call` ABI. | |
c1a9b12d SL |
105 | let inputs = &if abi == abi::RustCall { |
106 | untuple_arguments(cx, &sig.inputs) | |
107 | } else { | |
108 | sig.inputs | |
109 | }; | |
1a4d82fc JJ |
110 | |
111 | // Arg 0: Output pointer. | |
112 | // (if the output type is non-immediate) | |
113 | let lloutputtype = match sig.output { | |
114 | ty::FnConverging(output) => { | |
115 | let use_out_pointer = return_uses_outptr(cx, output); | |
116 | let lloutputtype = arg_type_of(cx, output); | |
117 | // Use the output as the actual return value if it's immediate. | |
118 | if use_out_pointer { | |
119 | atys.push(lloutputtype.ptr_to()); | |
120 | Type::void(cx) | |
121 | } else if return_type_is_void(cx, output) { | |
122 | Type::void(cx) | |
123 | } else { | |
124 | lloutputtype | |
125 | } | |
126 | } | |
127 | ty::FnDiverging => Type::void(cx) | |
128 | }; | |
129 | ||
130 | // Arg 1: Environment | |
131 | match llenvironment_type { | |
132 | None => {} | |
133 | Some(llenvironment_type) => atys.push(llenvironment_type), | |
134 | } | |
135 | ||
136 | // ... then explicit args. | |
c1a9b12d | 137 | for input in inputs { |
62682a34 SL |
138 | let arg_ty = type_of_explicit_arg(cx, input); |
139 | ||
140 | if type_is_fat_ptr(cx.tcx(), input) { | |
141 | atys.extend(arg_ty.field_types()); | |
142 | } else { | |
143 | atys.push(arg_ty); | |
144 | } | |
145 | } | |
1a4d82fc | 146 | |
85aaf69f | 147 | Type::func(&atys[..], &lloutputtype) |
1a4d82fc JJ |
148 | } |
149 | ||
150 | // Given a function type and a count of ty params, construct an llvm type | |
151 | pub fn type_of_fn_from_ty<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fty: Ty<'tcx>) -> Type { | |
152 | match fty.sty { | |
62682a34 | 153 | ty::TyBareFn(_, ref f) => { |
1a4d82fc JJ |
154 | // FIXME(#19925) once fn item types are |
155 | // zero-sized, we'll need to do something here | |
156 | if f.abi == abi::Rust || f.abi == abi::RustCall { | |
157 | type_of_rust_fn(cx, None, &f.sig, f.abi) | |
158 | } else { | |
159 | foreign::lltype_for_foreign_fn(cx, fty) | |
160 | } | |
161 | } | |
162 | _ => { | |
163 | cx.sess().bug("type_of_fn_from_ty given non-closure, non-bare-fn") | |
164 | } | |
165 | } | |
166 | } | |
167 | ||
168 | // A "sizing type" is an LLVM type, the size and alignment of which are | |
169 | // guaranteed to be equivalent to what you would get out of `type_of()`. It's | |
170 | // useful because: | |
171 | // | |
172 | // (1) It may be cheaper to compute the sizing type than the full type if all | |
173 | // you're interested in is the size and/or alignment; | |
174 | // | |
175 | // (2) It won't make any recursive calls to determine the structure of the | |
176 | // type behind pointers. This can help prevent infinite loops for | |
177 | // recursive types. For example, enum types rely on this behavior. | |
178 | ||
179 | pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type { | |
180 | match cx.llsizingtypes().borrow().get(&t).cloned() { | |
181 | Some(t) => return t, | |
182 | None => () | |
183 | } | |
184 | ||
185 | let llsizingty = match t.sty { | |
c34b1796 AL |
186 | _ if !type_is_sized(cx.tcx(), t) => { |
187 | Type::struct_(cx, &[Type::i8p(cx), Type::i8p(cx)], false) | |
1a4d82fc JJ |
188 | } |
189 | ||
62682a34 SL |
190 | ty::TyBool => Type::bool(cx), |
191 | ty::TyChar => Type::char(cx), | |
192 | ty::TyInt(t) => Type::int_from_ty(cx, t), | |
193 | ty::TyUint(t) => Type::uint_from_ty(cx, t), | |
194 | ty::TyFloat(t) => Type::float_from_ty(cx, t), | |
1a4d82fc | 195 | |
c1a9b12d SL |
196 | ty::TyBox(ty) | |
197 | ty::TyRef(_, ty::TypeAndMut{ty, ..}) | | |
198 | ty::TyRawPtr(ty::TypeAndMut{ty, ..}) => { | |
1a4d82fc JJ |
199 | if type_is_sized(cx.tcx(), ty) { |
200 | Type::i8p(cx) | |
201 | } else { | |
202 | Type::struct_(cx, &[Type::i8p(cx), Type::i8p(cx)], false) | |
203 | } | |
204 | } | |
205 | ||
62682a34 | 206 | ty::TyBareFn(..) => Type::i8p(cx), |
1a4d82fc | 207 | |
62682a34 | 208 | ty::TyArray(ty, size) => { |
1a4d82fc JJ |
209 | let llty = sizing_type_of(cx, ty); |
210 | let size = size as u64; | |
211 | ensure_array_fits_in_address_space(cx, llty, size, t); | |
212 | Type::array(&llty, size) | |
213 | } | |
214 | ||
62682a34 | 215 | ty::TyTuple(ref tys) if tys.is_empty() => { |
1a4d82fc JJ |
216 | Type::nil(cx) |
217 | } | |
218 | ||
62682a34 | 219 | ty::TyTuple(..) | ty::TyEnum(..) | ty::TyClosure(..) => { |
1a4d82fc JJ |
220 | let repr = adt::represent_type(cx, t); |
221 | adt::sizing_type_of(cx, &*repr, false) | |
222 | } | |
223 | ||
62682a34 | 224 | ty::TyStruct(..) => { |
c1a9b12d SL |
225 | if t.is_simd(cx.tcx()) { |
226 | let llet = type_of(cx, t.simd_type(cx.tcx())); | |
227 | let n = t.simd_size(cx.tcx()) as u64; | |
1a4d82fc JJ |
228 | ensure_array_fits_in_address_space(cx, llet, n, t); |
229 | Type::vector(&llet, n) | |
230 | } else { | |
231 | let repr = adt::represent_type(cx, t); | |
232 | adt::sizing_type_of(cx, &*repr, false) | |
233 | } | |
234 | } | |
235 | ||
62682a34 SL |
236 | ty::TyProjection(..) | ty::TyInfer(..) | ty::TyParam(..) | ty::TyError(..) => { |
237 | cx.sess().bug(&format!("fictitious type {:?} in sizing_type_of()", | |
238 | t)) | |
1a4d82fc | 239 | } |
62682a34 | 240 | ty::TySlice(_) | ty::TyTrait(..) | ty::TyStr => unreachable!() |
1a4d82fc JJ |
241 | }; |
242 | ||
243 | cx.llsizingtypes().borrow_mut().insert(t, llsizingty); | |
244 | llsizingty | |
245 | } | |
246 | ||
85aaf69f | 247 | pub fn foreign_arg_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type { |
c1a9b12d | 248 | if t.is_bool() { |
85aaf69f SL |
249 | Type::i1(cx) |
250 | } else { | |
251 | type_of(cx, t) | |
252 | } | |
253 | } | |
254 | ||
1a4d82fc | 255 | pub fn arg_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type { |
c1a9b12d | 256 | if t.is_bool() { |
1a4d82fc | 257 | Type::i1(cx) |
85aaf69f SL |
258 | } else if type_is_immediate(cx, t) && type_of(cx, t).is_aggregate() { |
259 | // We want to pass small aggregates as immediate values, but using an aggregate LLVM type | |
260 | // for this leads to bad optimizations, so its arg type is an appropriately sized integer | |
261 | match machine::llsize_of_alloc(cx, sizing_type_of(cx, t)) { | |
262 | 0 => type_of(cx, t), | |
263 | n => Type::ix(cx, n * 8), | |
264 | } | |
1a4d82fc JJ |
265 | } else { |
266 | type_of(cx, t) | |
267 | } | |
268 | } | |
269 | ||
c34b1796 AL |
270 | /// Get the LLVM type corresponding to a Rust type, i.e. `middle::ty::Ty`. |
271 | /// This is the right LLVM type for an alloca containing a value of that type, | |
272 | /// and the pointee of an Lvalue Datum (which is always a LLVM pointer). | |
273 | /// For unsized types, the returned type is a fat pointer, thus the resulting | |
274 | /// LLVM type for a `Trait` Lvalue is `{ i8*, void(i8*)** }*`, which is a double | |
275 | /// indirection to the actual data, unlike a `i8` Lvalue, which is just `i8*`. | |
276 | /// This is needed due to the treatment of immediate values, as a fat pointer | |
277 | /// is too large for it to be placed in SSA value (by our rules). | |
278 | /// For the raw type without far pointer indirection, see `in_memory_type_of`. | |
279 | pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type { | |
280 | let ty = if !type_is_sized(cx.tcx(), ty) { | |
c1a9b12d | 281 | cx.tcx().mk_imm_ptr(ty) |
c34b1796 AL |
282 | } else { |
283 | ty | |
284 | }; | |
285 | in_memory_type_of(cx, ty) | |
286 | } | |
1a4d82fc | 287 | |
c34b1796 AL |
288 | /// Get the LLVM type corresponding to a Rust type, i.e. `middle::ty::Ty`. |
289 | /// This is the right LLVM type for a field/array element of that type, | |
290 | /// and is the same as `type_of` for all Sized types. | |
291 | /// Unsized types, however, are represented by a "minimal unit", e.g. | |
292 | /// `[T]` becomes `T`, while `str` and `Trait` turn into `i8` - this | |
293 | /// is useful for indexing slices, as `&[T]`'s data pointer is `T*`. | |
294 | /// If the type is an unsized struct, the regular layout is generated, | |
295 | /// with the inner-most trailing unsized field using the "minimal unit" | |
296 | /// of that field's type - this is useful for taking the address of | |
297 | /// that field and ensuring the struct has the right alignment. | |
298 | /// For the LLVM type of a value as a whole, see `type_of`. | |
299 | /// NB: If you update this, be sure to update `sizing_type_of()` as well. | |
300 | pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type { | |
1a4d82fc JJ |
301 | // Check the cache. |
302 | match cx.lltypes().borrow().get(&t) { | |
303 | Some(&llty) => return llty, | |
304 | None => () | |
305 | } | |
306 | ||
62682a34 | 307 | debug!("type_of {:?}", t); |
1a4d82fc JJ |
308 | |
309 | assert!(!t.has_escaping_regions()); | |
310 | ||
311 | // Replace any typedef'd types with their equivalent non-typedef | |
312 | // type. This ensures that all LLVM nominal types that contain | |
313 | // Rust types are defined as the same LLVM types. If we don't do | |
314 | // this then, e.g. `Option<{myfield: bool}>` would be a different | |
315 | // type than `Option<myrec>`. | |
316 | let t_norm = erase_regions(cx.tcx(), &t); | |
317 | ||
318 | if t != t_norm { | |
c34b1796 | 319 | let llty = in_memory_type_of(cx, t_norm); |
62682a34 | 320 | debug!("--> normalized {:?} {:?} to {:?} {:?} llty={}", |
1a4d82fc | 321 | t, |
62682a34 SL |
322 | t, |
323 | t_norm, | |
1a4d82fc JJ |
324 | t_norm, |
325 | cx.tn().type_to_string(llty)); | |
326 | cx.lltypes().borrow_mut().insert(t, llty); | |
327 | return llty; | |
328 | } | |
329 | ||
330 | let mut llty = match t.sty { | |
62682a34 SL |
331 | ty::TyBool => Type::bool(cx), |
332 | ty::TyChar => Type::char(cx), | |
333 | ty::TyInt(t) => Type::int_from_ty(cx, t), | |
334 | ty::TyUint(t) => Type::uint_from_ty(cx, t), | |
335 | ty::TyFloat(t) => Type::float_from_ty(cx, t), | |
336 | ty::TyEnum(did, ref substs) => { | |
1a4d82fc JJ |
337 | // Only create the named struct, but don't fill it in. We |
338 | // fill it in *after* placing it into the type cache. This | |
339 | // avoids creating more than one copy of the enum when one | |
340 | // of the enum's variants refers to the enum itself. | |
341 | let repr = adt::represent_type(cx, t); | |
342 | let tps = substs.types.get_slice(subst::TypeSpace); | |
c34b1796 | 343 | let name = llvm_type_name(cx, did, tps); |
85aaf69f | 344 | adt::incomplete_type_of(cx, &*repr, &name[..]) |
1a4d82fc | 345 | } |
62682a34 | 346 | ty::TyClosure(..) => { |
1a4d82fc JJ |
347 | // Only create the named struct, but don't fill it in. We |
348 | // fill it in *after* placing it into the type cache. | |
349 | let repr = adt::represent_type(cx, t); | |
350 | // Unboxed closures can have substitutions in all spaces | |
351 | // inherited from their environment, so we use entire | |
352 | // contents of the VecPerParamSpace to to construct the llvm | |
353 | // name | |
c34b1796 | 354 | adt::incomplete_type_of(cx, &*repr, "closure") |
1a4d82fc JJ |
355 | } |
356 | ||
c1a9b12d SL |
357 | ty::TyBox(ty) | |
358 | ty::TyRef(_, ty::TypeAndMut{ty, ..}) | | |
359 | ty::TyRawPtr(ty::TypeAndMut{ty, ..}) => { | |
c34b1796 | 360 | if !type_is_sized(cx.tcx(), ty) { |
62682a34 | 361 | if let ty::TyStr = ty.sty { |
1a4d82fc JJ |
362 | // This means we get a nicer name in the output (str is always |
363 | // unsized). | |
364 | cx.tn().find_type("str_slice").unwrap() | |
c34b1796 AL |
365 | } else { |
366 | let ptr_ty = in_memory_type_of(cx, ty).ptr_to(); | |
c1a9b12d | 367 | let unsized_part = cx.tcx().struct_tail(ty); |
c34b1796 | 368 | let info_ty = match unsized_part.sty { |
62682a34 | 369 | ty::TyStr | ty::TyArray(..) | ty::TySlice(_) => { |
c34b1796 AL |
370 | Type::uint_from_ty(cx, ast::TyUs) |
371 | } | |
62682a34 | 372 | ty::TyTrait(_) => Type::vtable_ptr(cx), |
c34b1796 | 373 | _ => panic!("Unexpected type returned from \ |
62682a34 SL |
374 | struct_tail: {:?} for ty={:?}", |
375 | unsized_part, ty) | |
c34b1796 AL |
376 | }; |
377 | Type::struct_(cx, &[ptr_ty, info_ty], false) | |
1a4d82fc | 378 | } |
c34b1796 AL |
379 | } else { |
380 | in_memory_type_of(cx, ty).ptr_to() | |
1a4d82fc JJ |
381 | } |
382 | } | |
383 | ||
62682a34 | 384 | ty::TyArray(ty, size) => { |
1a4d82fc | 385 | let size = size as u64; |
c34b1796 | 386 | let llty = in_memory_type_of(cx, ty); |
1a4d82fc JJ |
387 | ensure_array_fits_in_address_space(cx, llty, size, t); |
388 | Type::array(&llty, size) | |
389 | } | |
1a4d82fc | 390 | |
c34b1796 AL |
391 | // Unsized slice types (and str) have the type of their element, and |
392 | // traits have the type of u8. This is so that the data pointer inside | |
393 | // fat pointers is of the right type (e.g. for array accesses), even | |
394 | // when taking the address of an unsized field in a struct. | |
62682a34 SL |
395 | ty::TySlice(ty) => in_memory_type_of(cx, ty), |
396 | ty::TyStr | ty::TyTrait(..) => Type::i8(cx), | |
1a4d82fc | 397 | |
62682a34 | 398 | ty::TyBareFn(..) => { |
1a4d82fc JJ |
399 | type_of_fn_from_ty(cx, t).ptr_to() |
400 | } | |
62682a34 SL |
401 | ty::TyTuple(ref tys) if tys.is_empty() => Type::nil(cx), |
402 | ty::TyTuple(..) => { | |
1a4d82fc JJ |
403 | let repr = adt::represent_type(cx, t); |
404 | adt::type_of(cx, &*repr) | |
405 | } | |
62682a34 | 406 | ty::TyStruct(did, ref substs) => { |
c1a9b12d SL |
407 | if t.is_simd(cx.tcx()) { |
408 | let llet = in_memory_type_of(cx, t.simd_type(cx.tcx())); | |
409 | let n = t.simd_size(cx.tcx()) as u64; | |
1a4d82fc JJ |
410 | ensure_array_fits_in_address_space(cx, llet, n, t); |
411 | Type::vector(&llet, n) | |
412 | } else { | |
413 | // Only create the named struct, but don't fill it in. We fill it | |
414 | // in *after* placing it into the type cache. This prevents | |
415 | // infinite recursion with recursive struct types. | |
416 | let repr = adt::represent_type(cx, t); | |
417 | let tps = substs.types.get_slice(subst::TypeSpace); | |
c34b1796 | 418 | let name = llvm_type_name(cx, did, tps); |
85aaf69f | 419 | adt::incomplete_type_of(cx, &*repr, &name[..]) |
1a4d82fc JJ |
420 | } |
421 | } | |
422 | ||
62682a34 SL |
423 | ty::TyInfer(..) => cx.sess().bug("type_of with TyInfer"), |
424 | ty::TyProjection(..) => cx.sess().bug("type_of with TyProjection"), | |
425 | ty::TyParam(..) => cx.sess().bug("type_of with ty_param"), | |
426 | ty::TyError(..) => cx.sess().bug("type_of with TyError"), | |
1a4d82fc JJ |
427 | }; |
428 | ||
62682a34 SL |
429 | debug!("--> mapped t={:?} {:?} to llty={}", |
430 | t, | |
1a4d82fc JJ |
431 | t, |
432 | cx.tn().type_to_string(llty)); | |
433 | ||
434 | cx.lltypes().borrow_mut().insert(t, llty); | |
435 | ||
436 | // If this was an enum or struct, fill in the type now. | |
437 | match t.sty { | |
62682a34 | 438 | ty::TyEnum(..) | ty::TyStruct(..) | ty::TyClosure(..) |
c1a9b12d | 439 | if !t.is_simd(cx.tcx()) => { |
1a4d82fc JJ |
440 | let repr = adt::represent_type(cx, t); |
441 | adt::finish_type_of(cx, &*repr, &mut llty); | |
442 | } | |
443 | _ => () | |
444 | } | |
445 | ||
c34b1796 | 446 | llty |
1a4d82fc JJ |
447 | } |
448 | ||
449 | pub fn align_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) | |
450 | -> machine::llalign { | |
451 | let llty = sizing_type_of(cx, t); | |
452 | machine::llalign_of_min(cx, llty) | |
453 | } | |
454 | ||
c34b1796 AL |
455 | fn llvm_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, |
456 | did: ast::DefId, | |
457 | tps: &[Ty<'tcx>]) | |
458 | -> String { | |
c1a9b12d | 459 | let base = cx.tcx().item_path_str(did); |
62682a34 | 460 | let strings: Vec<String> = tps.iter().map(|t| t.to_string()).collect(); |
1a4d82fc JJ |
461 | let tstr = if strings.is_empty() { |
462 | base | |
463 | } else { | |
c1a9b12d | 464 | format!("{}<{}>", base, strings.join(", ")) |
1a4d82fc JJ |
465 | }; |
466 | ||
467 | if did.krate == 0 { | |
c34b1796 | 468 | tstr |
1a4d82fc | 469 | } else { |
c34b1796 | 470 | format!("{}.{}", did.krate, tstr) |
1a4d82fc JJ |
471 | } |
472 | } | |
473 | ||
474 | pub fn type_of_dtor<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, self_ty: Ty<'tcx>) -> Type { | |
475 | let self_ty = type_of(ccx, self_ty).ptr_to(); | |
476 | Type::func(&[self_ty], &Type::void(ccx)) | |
477 | } |