]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/type_of.rs
Auto merge of #43651 - petrochenkov:foreign-life, r=eddyb
[rust.git] / src / librustc_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 use abi::FnType;
12 use adt;
13 use common::*;
14 use machine;
15 use rustc::ty::{self, Ty, TypeFoldable};
16 use rustc::ty::layout::LayoutTyper;
17 use trans_item::DefPathBasedNames;
18 use type_::Type;
19
20 use syntax::ast;
21
22 pub fn fat_ptr_base_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type {
23     match ty.sty {
24         ty::TyRef(_, ty::TypeAndMut { ty: t, .. }) |
25         ty::TyRawPtr(ty::TypeAndMut { ty: t, .. }) if !ccx.shared().type_is_sized(t) => {
26             in_memory_type_of(ccx, t).ptr_to()
27         }
28         ty::TyAdt(def, _) if def.is_box() => {
29             in_memory_type_of(ccx, ty.boxed_ty()).ptr_to()
30         }
31         _ => bug!("expected fat ptr ty but got {:?}", ty)
32     }
33 }
34
35 pub fn unsized_info_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type {
36     let unsized_part = ccx.tcx().struct_tail(ty);
37     match unsized_part.sty {
38         ty::TyStr | ty::TyArray(..) | ty::TySlice(_) => {
39             Type::uint_from_ty(ccx, ast::UintTy::Us)
40         }
41         ty::TyDynamic(..) => Type::vtable_ptr(ccx),
42         _ => bug!("Unexpected tail in unsized_info_ty: {:?} for ty={:?}",
43                           unsized_part, ty)
44     }
45 }
46
47 pub fn immediate_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
48     if t.is_bool() {
49         Type::i1(cx)
50     } else {
51         type_of(cx, t)
52     }
53 }
54
55 /// Get the LLVM type corresponding to a Rust type, i.e. `rustc::ty::Ty`.
56 /// This is the right LLVM type for an alloca containing a value of that type,
57 /// and the pointee of an Lvalue Datum (which is always a LLVM pointer).
58 /// For unsized types, the returned type is a fat pointer, thus the resulting
59 /// LLVM type for a `Trait` Lvalue is `{ i8*, void(i8*)** }*`, which is a double
60 /// indirection to the actual data, unlike a `i8` Lvalue, which is just `i8*`.
61 /// This is needed due to the treatment of immediate values, as a fat pointer
62 /// is too large for it to be placed in SSA value (by our rules).
63 /// For the raw type without far pointer indirection, see `in_memory_type_of`.
64 pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type {
65     let ty = if !cx.shared().type_is_sized(ty) {
66         cx.tcx().mk_imm_ptr(ty)
67     } else {
68         ty
69     };
70     in_memory_type_of(cx, ty)
71 }
72
73 /// Get the LLVM type corresponding to a Rust type, i.e. `rustc::ty::Ty`.
74 /// This is the right LLVM type for a field/array element of that type,
75 /// and is the same as `type_of` for all Sized types.
76 /// Unsized types, however, are represented by a "minimal unit", e.g.
77 /// `[T]` becomes `T`, while `str` and `Trait` turn into `i8` - this
78 /// is useful for indexing slices, as `&[T]`'s data pointer is `T*`.
79 /// If the type is an unsized struct, the regular layout is generated,
80 /// with the inner-most trailing unsized field using the "minimal unit"
81 /// of that field's type - this is useful for taking the address of
82 /// that field and ensuring the struct has the right alignment.
83 /// For the LLVM type of a value as a whole, see `type_of`.
84 pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
85     // Check the cache.
86     if let Some(&llty) = cx.lltypes().borrow().get(&t) {
87         return llty;
88     }
89
90     debug!("type_of {:?}", t);
91
92     assert!(!t.has_escaping_regions(), "{:?} has escaping regions", t);
93
94     // Replace any typedef'd types with their equivalent non-typedef
95     // type. This ensures that all LLVM nominal types that contain
96     // Rust types are defined as the same LLVM types.  If we don't do
97     // this then, e.g. `Option<{myfield: bool}>` would be a different
98     // type than `Option<myrec>`.
99     let t_norm = cx.tcx().erase_regions(&t);
100
101     if t != t_norm {
102         let llty = in_memory_type_of(cx, t_norm);
103         debug!("--> normalized {:?} to {:?} llty={:?}", t, t_norm, llty);
104         cx.lltypes().borrow_mut().insert(t, llty);
105         return llty;
106     }
107
108     let ptr_ty = |ty: Ty<'tcx>| {
109         if !cx.shared().type_is_sized(ty) {
110             if let ty::TyStr = ty.sty {
111                 // This means we get a nicer name in the output (str is always
112                 // unsized).
113                 cx.str_slice_type()
114             } else {
115                 let ptr_ty = in_memory_type_of(cx, ty).ptr_to();
116                 let info_ty = unsized_info_ty(cx, ty);
117                 Type::struct_(cx, &[ptr_ty, info_ty], false)
118             }
119         } else {
120             in_memory_type_of(cx, ty).ptr_to()
121         }
122     };
123
124     let mut llty = match t.sty {
125       ty::TyBool => Type::bool(cx),
126       ty::TyChar => Type::char(cx),
127       ty::TyInt(t) => Type::int_from_ty(cx, t),
128       ty::TyUint(t) => Type::uint_from_ty(cx, t),
129       ty::TyFloat(t) => Type::float_from_ty(cx, t),
130       ty::TyNever => Type::nil(cx),
131       ty::TyClosure(..) => {
132           // Only create the named struct, but don't fill it in. We
133           // fill it in *after* placing it into the type cache.
134           adt::incomplete_type_of(cx, t, "closure")
135       }
136
137       ty::TyRef(_, ty::TypeAndMut{ty, ..}) |
138       ty::TyRawPtr(ty::TypeAndMut{ty, ..}) => {
139           ptr_ty(ty)
140       }
141       ty::TyAdt(def, _) if def.is_box() => {
142           ptr_ty(t.boxed_ty())
143       }
144
145       ty::TyArray(ty, size) => {
146           let size = size as u64;
147           let llty = in_memory_type_of(cx, ty);
148           Type::array(&llty, size)
149       }
150
151       // Unsized slice types (and str) have the type of their element, and
152       // traits have the type of u8. This is so that the data pointer inside
153       // fat pointers is of the right type (e.g. for array accesses), even
154       // when taking the address of an unsized field in a struct.
155       ty::TySlice(ty) => in_memory_type_of(cx, ty),
156       ty::TyStr | ty::TyDynamic(..) => Type::i8(cx),
157
158       ty::TyFnDef(..) => Type::nil(cx),
159       ty::TyFnPtr(sig) => {
160         let sig = cx.tcx().erase_late_bound_regions_and_normalize(&sig);
161         FnType::new(cx, sig, &[]).llvm_type(cx).ptr_to()
162       }
163       ty::TyTuple(ref tys, _) if tys.is_empty() => Type::nil(cx),
164       ty::TyTuple(..) => {
165           adt::type_of(cx, t)
166       }
167       ty::TyAdt(..) if t.is_simd() => {
168           let e = t.simd_type(cx.tcx());
169           if !e.is_machine() {
170               cx.sess().fatal(&format!("monomorphising SIMD type `{}` with \
171                                         a non-machine element type `{}`",
172                                        t, e))
173           }
174           let llet = in_memory_type_of(cx, e);
175           let n = t.simd_size(cx.tcx()) as u64;
176           Type::vector(&llet, n)
177       }
178       ty::TyAdt(..) => {
179           // Only create the named struct, but don't fill it in. We
180           // fill it in *after* placing it into the type cache. This
181           // avoids creating more than one copy of the enum when one
182           // of the enum's variants refers to the enum itself.
183           let name = llvm_type_name(cx, t);
184           adt::incomplete_type_of(cx, t, &name[..])
185       }
186
187       ty::TyInfer(..) |
188       ty::TyProjection(..) |
189       ty::TyParam(..) |
190       ty::TyAnon(..) |
191       ty::TyError => bug!("type_of with {:?}", t),
192     };
193
194     debug!("--> mapped t={:?} to llty={:?}", t, llty);
195
196     cx.lltypes().borrow_mut().insert(t, llty);
197
198     // If this was an enum or struct, fill in the type now.
199     match t.sty {
200         ty::TyAdt(..) | ty::TyClosure(..) if !t.is_simd() && !t.is_box() => {
201             adt::finish_type_of(cx, t, &mut llty);
202         }
203         _ => ()
204     }
205
206     llty
207 }
208
209 impl<'a, 'tcx> CrateContext<'a, 'tcx> {
210     pub fn align_of(&self, ty: Ty<'tcx>) -> machine::llalign {
211         self.layout_of(ty).align(self).abi() as machine::llalign
212     }
213
214     pub fn size_of(&self, ty: Ty<'tcx>) -> machine::llsize {
215         self.layout_of(ty).size(self).bytes() as machine::llsize
216     }
217
218     pub fn over_align_of(&self, t: Ty<'tcx>)
219                               -> Option<machine::llalign> {
220         let layout = self.layout_of(t);
221         if let Some(align) = layout.over_align(&self.tcx().data_layout) {
222             Some(align as machine::llalign)
223         } else {
224             None
225         }
226     }
227 }
228
229 fn llvm_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> String {
230     let mut name = String::with_capacity(32);
231     let printer = DefPathBasedNames::new(cx.tcx(), true, true);
232     printer.push_type_name(ty, &mut name);
233     name
234 }