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