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