]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/trans/type_of.rs
Auto merge of #22541 - Manishearth:rollup, r=Gankro
[rust.git] / src / librustc_trans / trans / type_of.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 #![allow(non_camel_case_types)]
12
13 pub use self::named_ty::*;
14
15 use middle::subst;
16 use trans::adt;
17 use trans::common::*;
18 use trans::foreign;
19 use trans::machine;
20 use middle::ty::{self, RegionEscape, Ty};
21 use util::ppaux;
22 use util::ppaux::Repr;
23
24 use trans::type_::Type;
25
26 use std::num::Int;
27 use syntax::abi;
28 use syntax::ast;
29
30 // LLVM doesn't like objects that are too big. Issue #17913
31 fn ensure_array_fits_in_address_space<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
32                                                 llet: Type,
33                                                 size: machine::llsize,
34                                                 scapegoat: Ty<'tcx>) {
35     let esz = machine::llsize_of_alloc(ccx, llet);
36     match esz.checked_mul(size) {
37         Some(n) if n < ccx.obj_size_bound() => {}
38         _ => { ccx.report_overbig_object(scapegoat) }
39     }
40 }
41
42 pub fn arg_is_indirect<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
43                                  arg_ty: Ty<'tcx>) -> bool {
44     !type_is_immediate(ccx, arg_ty)
45 }
46
47 pub fn return_uses_outptr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
48                                     ty: Ty<'tcx>) -> bool {
49     !type_is_immediate(ccx, ty)
50 }
51
52 pub fn type_of_explicit_arg<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
53                                       arg_ty: Ty<'tcx>) -> Type {
54     let llty = arg_type_of(ccx, arg_ty);
55     if arg_is_indirect(ccx, arg_ty) {
56         llty.ptr_to()
57     } else {
58         llty
59     }
60 }
61
62 /// Yields the types of the "real" arguments for this function. For most
63 /// functions, these are simply the types of the arguments. For functions with
64 /// the `RustCall` ABI, however, this untuples the arguments of the function.
65 pub fn untuple_arguments_if_necessary<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
66                                                 inputs: &[Ty<'tcx>],
67                                                 abi: abi::Abi)
68                                                 -> Vec<Ty<'tcx>> {
69     if abi != abi::RustCall {
70         return inputs.iter().cloned().collect()
71     }
72
73     if inputs.len() == 0 {
74         return Vec::new()
75     }
76
77     let mut result = Vec::new();
78     for (i, &arg_prior_to_tuple) in inputs.iter().enumerate() {
79         if i < inputs.len() - 1 {
80             result.push(arg_prior_to_tuple);
81         }
82     }
83
84     match inputs[inputs.len() - 1].sty {
85         ty::ty_tup(ref tupled_arguments) => {
86             debug!("untuple_arguments_if_necessary(): untupling arguments");
87             for &tupled_argument in tupled_arguments {
88                 result.push(tupled_argument);
89             }
90         }
91         _ => {
92             ccx.tcx().sess.bug("argument to function with \"rust-call\" ABI \
93                                 is neither a tuple nor unit")
94         }
95     }
96
97     result
98 }
99
100 pub fn type_of_rust_fn<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
101                                  llenvironment_type: Option<Type>,
102                                  sig: &ty::Binder<ty::FnSig<'tcx>>,
103                                  abi: abi::Abi)
104                                  -> Type
105 {
106     debug!("type_of_rust_fn(sig={},abi={:?})",
107            sig.repr(cx.tcx()),
108            abi);
109
110     let sig = ty::erase_late_bound_regions(cx.tcx(), sig);
111     assert!(!sig.variadic); // rust fns are never variadic
112
113     let mut atys: Vec<Type> = Vec::new();
114
115     // First, munge the inputs, if this has the `rust-call` ABI.
116     let inputs = untuple_arguments_if_necessary(cx, &sig.inputs, abi);
117
118     // Arg 0: Output pointer.
119     // (if the output type is non-immediate)
120     let lloutputtype = match sig.output {
121         ty::FnConverging(output) => {
122             let use_out_pointer = return_uses_outptr(cx, output);
123             let lloutputtype = arg_type_of(cx, output);
124             // Use the output as the actual return value if it's immediate.
125             if use_out_pointer {
126                 atys.push(lloutputtype.ptr_to());
127                 Type::void(cx)
128             } else if return_type_is_void(cx, output) {
129                 Type::void(cx)
130             } else {
131                 lloutputtype
132             }
133         }
134         ty::FnDiverging => Type::void(cx)
135     };
136
137     // Arg 1: Environment
138     match llenvironment_type {
139         None => {}
140         Some(llenvironment_type) => atys.push(llenvironment_type),
141     }
142
143     // ... then explicit args.
144     let input_tys = inputs.iter().map(|&arg_ty| type_of_explicit_arg(cx, arg_ty));
145     atys.extend(input_tys);
146
147     Type::func(&atys[..], &lloutputtype)
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 {
153         ty::ty_bare_fn(_, ref f) => {
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 {
186         _ if !lltype_is_sized(cx.tcx(), t) => {
187             cx.sess().bug(&format!("trying to take the sizing type of {}, an unsized type",
188                                   ppaux::ty_to_string(cx.tcx(), t))[])
189         }
190
191         ty::ty_bool => Type::bool(cx),
192         ty::ty_char => Type::char(cx),
193         ty::ty_int(t) => Type::int_from_ty(cx, t),
194         ty::ty_uint(t) => Type::uint_from_ty(cx, t),
195         ty::ty_float(t) => Type::float_from_ty(cx, t),
196
197         ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) | ty::ty_ptr(ty::mt{ty, ..}) => {
198             if type_is_sized(cx.tcx(), ty) {
199                 Type::i8p(cx)
200             } else {
201                 Type::struct_(cx, &[Type::i8p(cx), Type::i8p(cx)], false)
202             }
203         }
204
205         ty::ty_bare_fn(..) => Type::i8p(cx),
206
207         ty::ty_vec(ty, Some(size)) => {
208             let llty = sizing_type_of(cx, ty);
209             let size = size as u64;
210             ensure_array_fits_in_address_space(cx, llty, size, t);
211             Type::array(&llty, size)
212         }
213
214         ty::ty_tup(ref tys) if tys.is_empty() => {
215             Type::nil(cx)
216         }
217
218         ty::ty_tup(..) | ty::ty_enum(..) | ty::ty_closure(..) => {
219             let repr = adt::represent_type(cx, t);
220             adt::sizing_type_of(cx, &*repr, false)
221         }
222
223         ty::ty_struct(..) => {
224             if ty::type_is_simd(cx.tcx(), t) {
225                 let llet = type_of(cx, ty::simd_type(cx.tcx(), t));
226                 let n = ty::simd_size(cx.tcx(), t) as u64;
227                 ensure_array_fits_in_address_space(cx, llet, n, t);
228                 Type::vector(&llet, n)
229             } else {
230                 let repr = adt::represent_type(cx, t);
231                 adt::sizing_type_of(cx, &*repr, false)
232             }
233         }
234
235         ty::ty_open(_) => {
236             Type::struct_(cx, &[Type::i8p(cx), Type::i8p(cx)], false)
237         }
238
239         ty::ty_projection(..) | ty::ty_infer(..) | ty::ty_param(..) | ty::ty_err(..) => {
240             cx.sess().bug(&format!("fictitious type {} in sizing_type_of()",
241                                   ppaux::ty_to_string(cx.tcx(), t))[])
242         }
243         ty::ty_vec(_, None) | ty::ty_trait(..) | ty::ty_str => panic!("unreachable")
244     };
245
246     cx.llsizingtypes().borrow_mut().insert(t, llsizingty);
247     llsizingty
248 }
249
250 pub fn foreign_arg_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
251     if ty::type_is_bool(t) {
252         Type::i1(cx)
253     } else {
254         type_of(cx, t)
255     }
256 }
257
258 pub fn arg_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
259     if ty::type_is_bool(t) {
260         Type::i1(cx)
261     } else if type_is_immediate(cx, t) && type_of(cx, t).is_aggregate() {
262         // We want to pass small aggregates as immediate values, but using an aggregate LLVM type
263         // for this leads to bad optimizations, so its arg type is an appropriately sized integer
264         match machine::llsize_of_alloc(cx, sizing_type_of(cx, t)) {
265             0 => type_of(cx, t),
266             n => Type::ix(cx, n * 8),
267         }
268     } else {
269         type_of(cx, t)
270     }
271 }
272
273 // NB: If you update this, be sure to update `sizing_type_of()` as well.
274 pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
275     fn type_of_unsize_info<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
276         // It is possible to end up here with a sized type. This happens with a
277         // struct which might be unsized, but is monomorphised to a sized type.
278         // In this case we'll fake a fat pointer with no unsize info (we use 0).
279         // However, its still a fat pointer, so we need some type use.
280         if type_is_sized(cx.tcx(), t) {
281             return Type::i8p(cx);
282         }
283
284         match unsized_part_of_type(cx.tcx(), t).sty {
285             ty::ty_str | ty::ty_vec(..) => Type::uint_from_ty(cx, ast::TyUs(false)),
286             ty::ty_trait(_) => Type::vtable_ptr(cx),
287             _ => panic!("Unexpected type returned from unsized_part_of_type : {}",
288                        t.repr(cx.tcx()))
289         }
290     }
291
292     // Check the cache.
293     match cx.lltypes().borrow().get(&t) {
294         Some(&llty) => return llty,
295         None => ()
296     }
297
298     debug!("type_of {} {:?}", t.repr(cx.tcx()), t.sty);
299
300     assert!(!t.has_escaping_regions());
301
302     // Replace any typedef'd types with their equivalent non-typedef
303     // type. This ensures that all LLVM nominal types that contain
304     // Rust types are defined as the same LLVM types.  If we don't do
305     // this then, e.g. `Option<{myfield: bool}>` would be a different
306     // type than `Option<myrec>`.
307     let t_norm = erase_regions(cx.tcx(), &t);
308
309     if t != t_norm {
310         let llty = type_of(cx, t_norm);
311         debug!("--> normalized {} {:?} to {} {:?} llty={}",
312                 t.repr(cx.tcx()),
313                 t,
314                 t_norm.repr(cx.tcx()),
315                 t_norm,
316                 cx.tn().type_to_string(llty));
317         cx.lltypes().borrow_mut().insert(t, llty);
318         return llty;
319     }
320
321     let mut llty = match t.sty {
322       ty::ty_bool => Type::bool(cx),
323       ty::ty_char => Type::char(cx),
324       ty::ty_int(t) => Type::int_from_ty(cx, t),
325       ty::ty_uint(t) => Type::uint_from_ty(cx, t),
326       ty::ty_float(t) => Type::float_from_ty(cx, t),
327       ty::ty_enum(did, ref substs) => {
328           // Only create the named struct, but don't fill it in. We
329           // fill it in *after* placing it into the type cache. This
330           // avoids creating more than one copy of the enum when one
331           // of the enum's variants refers to the enum itself.
332           let repr = adt::represent_type(cx, t);
333           let tps = substs.types.get_slice(subst::TypeSpace);
334           let name = llvm_type_name(cx, an_enum, did, tps);
335           adt::incomplete_type_of(cx, &*repr, &name[..])
336       }
337       ty::ty_closure(did, _, ref substs) => {
338           // Only create the named struct, but don't fill it in. We
339           // fill it in *after* placing it into the type cache.
340           let repr = adt::represent_type(cx, t);
341           // Unboxed closures can have substitutions in all spaces
342           // inherited from their environment, so we use entire
343           // contents of the VecPerParamSpace to to construct the llvm
344           // name
345           let name = llvm_type_name(cx, a_closure, did, substs.types.as_slice());
346           adt::incomplete_type_of(cx, &*repr, &name[..])
347       }
348
349       ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) | ty::ty_ptr(ty::mt{ty, ..}) => {
350           match ty.sty {
351               ty::ty_str => {
352                   // This means we get a nicer name in the output (str is always
353                   // unsized).
354                   cx.tn().find_type("str_slice").unwrap()
355               }
356               ty::ty_trait(..) => Type::opaque_trait(cx),
357               _ if !type_is_sized(cx.tcx(), ty) => {
358                   let p_ty = type_of(cx, ty).ptr_to();
359                   Type::struct_(cx, &[p_ty, type_of_unsize_info(cx, ty)], false)
360               }
361               _ => type_of(cx, ty).ptr_to(),
362           }
363       }
364
365       ty::ty_vec(ty, Some(size)) => {
366           let size = size as u64;
367           let llty = type_of(cx, ty);
368           ensure_array_fits_in_address_space(cx, llty, size, t);
369           Type::array(&llty, size)
370       }
371       ty::ty_vec(ty, None) => {
372           type_of(cx, ty)
373       }
374
375       ty::ty_trait(..) => {
376           Type::opaque_trait_data(cx)
377       }
378
379       ty::ty_str => Type::i8(cx),
380
381       ty::ty_bare_fn(..) => {
382           type_of_fn_from_ty(cx, t).ptr_to()
383       }
384       ty::ty_tup(ref tys) if tys.is_empty() => Type::nil(cx),
385       ty::ty_tup(..) => {
386           let repr = adt::represent_type(cx, t);
387           adt::type_of(cx, &*repr)
388       }
389       ty::ty_struct(did, ref substs) => {
390           if ty::type_is_simd(cx.tcx(), t) {
391               let llet = type_of(cx, ty::simd_type(cx.tcx(), t));
392               let n = ty::simd_size(cx.tcx(), t) as u64;
393               ensure_array_fits_in_address_space(cx, llet, n, t);
394               Type::vector(&llet, n)
395           } else {
396               // Only create the named struct, but don't fill it in. We fill it
397               // in *after* placing it into the type cache. This prevents
398               // infinite recursion with recursive struct types.
399               let repr = adt::represent_type(cx, t);
400               let tps = substs.types.get_slice(subst::TypeSpace);
401               let name = llvm_type_name(cx, a_struct, did, tps);
402               adt::incomplete_type_of(cx, &*repr, &name[..])
403           }
404       }
405
406       ty::ty_open(t) => match t.sty {
407           ty::ty_struct(..) => {
408               let p_ty = type_of(cx, t).ptr_to();
409               Type::struct_(cx, &[p_ty, type_of_unsize_info(cx, t)], false)
410           }
411           ty::ty_vec(ty, None) => {
412               let p_ty = type_of(cx, ty).ptr_to();
413               Type::struct_(cx, &[p_ty, type_of_unsize_info(cx, t)], false)
414           }
415           ty::ty_str => {
416               let p_ty = Type::i8p(cx);
417               Type::struct_(cx, &[p_ty, type_of_unsize_info(cx, t)], false)
418           }
419           ty::ty_trait(..) => Type::opaque_trait(cx),
420           _ => cx.sess().bug(&format!("ty_open with sized type: {}",
421                                      ppaux::ty_to_string(cx.tcx(), t))[])
422       },
423
424       ty::ty_infer(..) => cx.sess().bug("type_of with ty_infer"),
425       ty::ty_projection(..) => cx.sess().bug("type_of with ty_projection"),
426       ty::ty_param(..) => cx.sess().bug("type_of with ty_param"),
427       ty::ty_err(..) => cx.sess().bug("type_of with ty_err"),
428     };
429
430     debug!("--> mapped t={} {:?} to llty={}",
431             t.repr(cx.tcx()),
432             t,
433             cx.tn().type_to_string(llty));
434
435     cx.lltypes().borrow_mut().insert(t, llty);
436
437     // If this was an enum or struct, fill in the type now.
438     match t.sty {
439         ty::ty_enum(..) | ty::ty_struct(..) | ty::ty_closure(..)
440                 if !ty::type_is_simd(cx.tcx(), t) => {
441             let repr = adt::represent_type(cx, t);
442             adt::finish_type_of(cx, &*repr, &mut llty);
443         }
444         _ => ()
445     }
446
447     return llty;
448 }
449
450 pub fn align_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>)
451                           -> machine::llalign {
452     let llty = sizing_type_of(cx, t);
453     machine::llalign_of_min(cx, llty)
454 }
455
456 // Want refinements! (Or case classes, I guess
457 #[derive(Copy)]
458 pub enum named_ty {
459     a_struct,
460     an_enum,
461     a_closure,
462 }
463
464 pub fn llvm_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
465                                 what: named_ty,
466                                 did: ast::DefId,
467                                 tps: &[Ty<'tcx>])
468                                 -> String {
469     let name = match what {
470         a_struct => "struct",
471         an_enum => "enum",
472         a_closure => return "closure".to_string(),
473     };
474
475     let base = ty::item_path_str(cx.tcx(), did);
476     let strings: Vec<String> = tps.iter().map(|t| t.repr(cx.tcx())).collect();
477     let tstr = if strings.is_empty() {
478         base
479     } else {
480         format!("{}<{:?}>", base, strings)
481     };
482
483     if did.krate == 0 {
484         format!("{}.{}", name, tstr)
485     } else {
486         format!("{}.{}[{}{}]", name, tstr, "#", did.krate)
487     }
488 }
489
490 pub fn type_of_dtor<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, self_ty: Ty<'tcx>) -> Type {
491     let self_ty = type_of(ccx, self_ty).ptr_to();
492     Type::func(&[self_ty], &Type::void(ccx))
493 }