]> git.proxmox.com Git - rustc.git/blame - src/librustc_trans/type_of.rs
New upstream version 1.12.0+dfsg1
[rustc.git] / src / librustc_trans / type_of.rs
CommitLineData
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
54a0048b 13use rustc::hir::def_id::DefId;
54a0048b
SL
14use rustc::ty::subst;
15use abi::FnType;
16use adt;
17use common::*;
18use machine;
5bcae85e 19use rustc::traits::Reveal;
54a0048b
SL
20use rustc::ty::{self, Ty, TypeFoldable};
21
22use type_::Type;
23
b039eaaf 24use syntax::ast;
1a4d82fc
JJ
25
26// LLVM doesn't like objects that are too big. Issue #17913
27fn ensure_array_fits_in_address_space<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
28 llet: Type,
29 size: machine::llsize,
30 scapegoat: Ty<'tcx>) {
31 let esz = machine::llsize_of_alloc(ccx, llet);
32 match esz.checked_mul(size) {
33 Some(n) if n < ccx.obj_size_bound() => {}
34 _ => { ccx.report_overbig_object(scapegoat) }
35 }
36}
37
1a4d82fc
JJ
38// A "sizing type" is an LLVM type, the size and alignment of which are
39// guaranteed to be equivalent to what you would get out of `type_of()`. It's
40// useful because:
41//
42// (1) It may be cheaper to compute the sizing type than the full type if all
43// you're interested in is the size and/or alignment;
44//
45// (2) It won't make any recursive calls to determine the structure of the
46// type behind pointers. This can help prevent infinite loops for
47// recursive types. For example, enum types rely on this behavior.
48
49pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
7453a54e
SL
50 if let Some(t) = cx.llsizingtypes().borrow().get(&t).cloned() {
51 return t;
1a4d82fc
JJ
52 }
53
e9174d1e 54 debug!("sizing_type_of {:?}", t);
92a42be0
SL
55 let _recursion_lock = cx.enter_type_of(t);
56
1a4d82fc 57 let llsizingty = match t.sty {
c34b1796 58 _ if !type_is_sized(cx.tcx(), t) => {
54a0048b 59 Type::struct_(cx, &[Type::i8p(cx), unsized_info_ty(cx, t)], false)
1a4d82fc
JJ
60 }
61
62682a34
SL
62 ty::TyBool => Type::bool(cx),
63 ty::TyChar => Type::char(cx),
64 ty::TyInt(t) => Type::int_from_ty(cx, t),
65 ty::TyUint(t) => Type::uint_from_ty(cx, t),
66 ty::TyFloat(t) => Type::float_from_ty(cx, t),
5bcae85e 67 ty::TyNever => Type::nil(cx),
1a4d82fc 68
c1a9b12d
SL
69 ty::TyBox(ty) |
70 ty::TyRef(_, ty::TypeAndMut{ty, ..}) |
71 ty::TyRawPtr(ty::TypeAndMut{ty, ..}) => {
1a4d82fc
JJ
72 if type_is_sized(cx.tcx(), ty) {
73 Type::i8p(cx)
74 } else {
54a0048b 75 Type::struct_(cx, &[Type::i8p(cx), unsized_info_ty(cx, ty)], false)
1a4d82fc
JJ
76 }
77 }
78
54a0048b
SL
79 ty::TyFnDef(..) => Type::nil(cx),
80 ty::TyFnPtr(_) => Type::i8p(cx),
1a4d82fc 81
62682a34 82 ty::TyArray(ty, size) => {
1a4d82fc
JJ
83 let llty = sizing_type_of(cx, ty);
84 let size = size as u64;
85 ensure_array_fits_in_address_space(cx, llty, size, t);
86 Type::array(&llty, size)
87 }
88
62682a34 89 ty::TyTuple(ref tys) if tys.is_empty() => {
1a4d82fc
JJ
90 Type::nil(cx)
91 }
92
62682a34 93 ty::TyTuple(..) | ty::TyEnum(..) | ty::TyClosure(..) => {
1a4d82fc 94 let repr = adt::represent_type(cx, t);
7453a54e 95 adt::sizing_type_of(cx, &repr, false)
1a4d82fc
JJ
96 }
97
62682a34 98 ty::TyStruct(..) => {
e9174d1e
SL
99 if t.is_simd() {
100 let e = t.simd_type(cx.tcx());
101 if !e.is_machine() {
102 cx.sess().fatal(&format!("monomorphising SIMD type `{}` with \
103 a non-machine element type `{}`",
104 t, e))
105 }
106 let llet = type_of(cx, e);
c1a9b12d 107 let n = t.simd_size(cx.tcx()) as u64;
1a4d82fc
JJ
108 ensure_array_fits_in_address_space(cx, llet, n, t);
109 Type::vector(&llet, n)
110 } else {
111 let repr = adt::represent_type(cx, t);
7453a54e 112 adt::sizing_type_of(cx, &repr, false)
1a4d82fc
JJ
113 }
114 }
115
5bcae85e
SL
116 ty::TyProjection(..) | ty::TyInfer(..) | ty::TyParam(..) |
117 ty::TyAnon(..) | ty::TyError => {
54a0048b 118 bug!("fictitious type {:?} in sizing_type_of()", t)
1a4d82fc 119 }
54a0048b 120 ty::TySlice(_) | ty::TyTrait(..) | ty::TyStr => bug!()
1a4d82fc
JJ
121 };
122
54a0048b 123 debug!("--> mapped t={:?} to llsizingty={:?}", t, llsizingty);
e9174d1e 124
1a4d82fc 125 cx.llsizingtypes().borrow_mut().insert(t, llsizingty);
54a0048b
SL
126
127 // FIXME(eddyb) Temporary sanity check for ty::layout.
5bcae85e 128 let layout = cx.tcx().normalizing_infer_ctxt(Reveal::All).enter(|infcx| {
a7813a04
XL
129 t.layout(&infcx)
130 });
131 match layout {
54a0048b
SL
132 Ok(layout) => {
133 if !type_is_sized(cx.tcx(), t) {
134 if !layout.is_unsized() {
135 bug!("layout should be unsized for type `{}` / {:#?}",
136 t, layout);
137 }
138
139 // Unsized types get turned into a fat pointer for LLVM.
140 return llsizingty;
141 }
142 let r = layout.size(&cx.tcx().data_layout).bytes();
143 let l = machine::llsize_of_alloc(cx, llsizingty);
144 if r != l {
145 bug!("size differs (rustc: {}, llvm: {}) for type `{}` / {:#?}",
146 r, l, t, layout);
147 }
148 let r = layout.align(&cx.tcx().data_layout).abi();
149 let l = machine::llalign_of_min(cx, llsizingty) as u64;
150 if r != l {
151 bug!("align differs (rustc: {}, llvm: {}) for type `{}` / {:#?}",
152 r, l, t, layout);
153 }
154 }
155 Err(e) => {
156 bug!("failed to get layout for `{}`: {}", t, e);
157 }
158 }
1a4d82fc
JJ
159 llsizingty
160}
161
a7813a04
XL
162pub fn fat_ptr_base_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type {
163 match ty.sty {
164 ty::TyBox(t) |
165 ty::TyRef(_, ty::TypeAndMut { ty: t, .. }) |
166 ty::TyRawPtr(ty::TypeAndMut { ty: t, .. }) if !type_is_sized(ccx.tcx(), t) => {
167 in_memory_type_of(ccx, t).ptr_to()
168 }
169 _ => bug!("expected fat ptr ty but got {:?}", ty)
170 }
171}
172
54a0048b
SL
173fn unsized_info_ty<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type {
174 let unsized_part = ccx.tcx().struct_tail(ty);
175 match unsized_part.sty {
176 ty::TyStr | ty::TyArray(..) | ty::TySlice(_) => {
177 Type::uint_from_ty(ccx, ast::UintTy::Us)
178 }
179 ty::TyTrait(_) => Type::vtable_ptr(ccx),
180 _ => bug!("Unexpected tail in unsized_info_ty: {:?} for ty={:?}",
181 unsized_part, ty)
85aaf69f
SL
182 }
183}
184
54a0048b 185pub fn immediate_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
c1a9b12d 186 if t.is_bool() {
1a4d82fc
JJ
187 Type::i1(cx)
188 } else {
189 type_of(cx, t)
190 }
191}
192
54a0048b 193/// Get the LLVM type corresponding to a Rust type, i.e. `rustc::ty::Ty`.
c34b1796
AL
194/// This is the right LLVM type for an alloca containing a value of that type,
195/// and the pointee of an Lvalue Datum (which is always a LLVM pointer).
196/// For unsized types, the returned type is a fat pointer, thus the resulting
197/// LLVM type for a `Trait` Lvalue is `{ i8*, void(i8*)** }*`, which is a double
198/// indirection to the actual data, unlike a `i8` Lvalue, which is just `i8*`.
199/// This is needed due to the treatment of immediate values, as a fat pointer
200/// is too large for it to be placed in SSA value (by our rules).
201/// For the raw type without far pointer indirection, see `in_memory_type_of`.
202pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type {
203 let ty = if !type_is_sized(cx.tcx(), ty) {
c1a9b12d 204 cx.tcx().mk_imm_ptr(ty)
c34b1796
AL
205 } else {
206 ty
207 };
208 in_memory_type_of(cx, ty)
209}
1a4d82fc 210
54a0048b 211/// Get the LLVM type corresponding to a Rust type, i.e. `rustc::ty::Ty`.
c34b1796
AL
212/// This is the right LLVM type for a field/array element of that type,
213/// and is the same as `type_of` for all Sized types.
214/// Unsized types, however, are represented by a "minimal unit", e.g.
215/// `[T]` becomes `T`, while `str` and `Trait` turn into `i8` - this
216/// is useful for indexing slices, as `&[T]`'s data pointer is `T*`.
217/// If the type is an unsized struct, the regular layout is generated,
218/// with the inner-most trailing unsized field using the "minimal unit"
219/// of that field's type - this is useful for taking the address of
220/// that field and ensuring the struct has the right alignment.
221/// For the LLVM type of a value as a whole, see `type_of`.
222/// NB: If you update this, be sure to update `sizing_type_of()` as well.
223pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
1a4d82fc 224 // Check the cache.
7453a54e
SL
225 if let Some(&llty) = cx.lltypes().borrow().get(&t) {
226 return llty;
1a4d82fc
JJ
227 }
228
62682a34 229 debug!("type_of {:?}", t);
1a4d82fc 230
54a0048b 231 assert!(!t.has_escaping_regions(), "{:?} has escaping regions", t);
1a4d82fc
JJ
232
233 // Replace any typedef'd types with their equivalent non-typedef
234 // type. This ensures that all LLVM nominal types that contain
235 // Rust types are defined as the same LLVM types. If we don't do
236 // this then, e.g. `Option<{myfield: bool}>` would be a different
237 // type than `Option<myrec>`.
e9174d1e 238 let t_norm = cx.tcx().erase_regions(&t);
1a4d82fc
JJ
239
240 if t != t_norm {
c34b1796 241 let llty = in_memory_type_of(cx, t_norm);
54a0048b 242 debug!("--> normalized {:?} to {:?} llty={:?}", t, t_norm, llty);
1a4d82fc
JJ
243 cx.lltypes().borrow_mut().insert(t, llty);
244 return llty;
245 }
246
247 let mut llty = match t.sty {
62682a34
SL
248 ty::TyBool => Type::bool(cx),
249 ty::TyChar => Type::char(cx),
250 ty::TyInt(t) => Type::int_from_ty(cx, t),
251 ty::TyUint(t) => Type::uint_from_ty(cx, t),
252 ty::TyFloat(t) => Type::float_from_ty(cx, t),
5bcae85e 253 ty::TyNever => Type::nil(cx),
e9174d1e 254 ty::TyEnum(def, ref substs) => {
1a4d82fc
JJ
255 // Only create the named struct, but don't fill it in. We
256 // fill it in *after* placing it into the type cache. This
257 // avoids creating more than one copy of the enum when one
258 // of the enum's variants refers to the enum itself.
259 let repr = adt::represent_type(cx, t);
260 let tps = substs.types.get_slice(subst::TypeSpace);
e9174d1e 261 let name = llvm_type_name(cx, def.did, tps);
7453a54e 262 adt::incomplete_type_of(cx, &repr, &name[..])
1a4d82fc 263 }
62682a34 264 ty::TyClosure(..) => {
1a4d82fc
JJ
265 // Only create the named struct, but don't fill it in. We
266 // fill it in *after* placing it into the type cache.
267 let repr = adt::represent_type(cx, t);
268 // Unboxed closures can have substitutions in all spaces
269 // inherited from their environment, so we use entire
b039eaaf 270 // contents of the VecPerParamSpace to construct the llvm
1a4d82fc 271 // name
7453a54e 272 adt::incomplete_type_of(cx, &repr, "closure")
1a4d82fc
JJ
273 }
274
c1a9b12d
SL
275 ty::TyBox(ty) |
276 ty::TyRef(_, ty::TypeAndMut{ty, ..}) |
277 ty::TyRawPtr(ty::TypeAndMut{ty, ..}) => {
c34b1796 278 if !type_is_sized(cx.tcx(), ty) {
62682a34 279 if let ty::TyStr = ty.sty {
1a4d82fc
JJ
280 // This means we get a nicer name in the output (str is always
281 // unsized).
282 cx.tn().find_type("str_slice").unwrap()
c34b1796
AL
283 } else {
284 let ptr_ty = in_memory_type_of(cx, ty).ptr_to();
54a0048b 285 let info_ty = unsized_info_ty(cx, ty);
c34b1796 286 Type::struct_(cx, &[ptr_ty, info_ty], false)
1a4d82fc 287 }
c34b1796
AL
288 } else {
289 in_memory_type_of(cx, ty).ptr_to()
1a4d82fc
JJ
290 }
291 }
292
62682a34 293 ty::TyArray(ty, size) => {
1a4d82fc 294 let size = size as u64;
92a42be0
SL
295 // we must use `sizing_type_of` here as the type may
296 // not be fully initialized.
297 let szty = sizing_type_of(cx, ty);
298 ensure_array_fits_in_address_space(cx, szty, size, t);
299
c34b1796 300 let llty = in_memory_type_of(cx, ty);
1a4d82fc
JJ
301 Type::array(&llty, size)
302 }
1a4d82fc 303
c34b1796
AL
304 // Unsized slice types (and str) have the type of their element, and
305 // traits have the type of u8. This is so that the data pointer inside
306 // fat pointers is of the right type (e.g. for array accesses), even
307 // when taking the address of an unsized field in a struct.
62682a34
SL
308 ty::TySlice(ty) => in_memory_type_of(cx, ty),
309 ty::TyStr | ty::TyTrait(..) => Type::i8(cx),
1a4d82fc 310
54a0048b
SL
311 ty::TyFnDef(..) => Type::nil(cx),
312 ty::TyFnPtr(f) => {
313 let sig = cx.tcx().erase_late_bound_regions(&f.sig);
a7813a04 314 let sig = cx.tcx().normalize_associated_type(&sig);
54a0048b 315 FnType::new(cx, f.abi, &sig, &[]).llvm_type(cx).ptr_to()
1a4d82fc 316 }
62682a34
SL
317 ty::TyTuple(ref tys) if tys.is_empty() => Type::nil(cx),
318 ty::TyTuple(..) => {
1a4d82fc 319 let repr = adt::represent_type(cx, t);
7453a54e 320 adt::type_of(cx, &repr)
1a4d82fc 321 }
e9174d1e
SL
322 ty::TyStruct(def, ref substs) => {
323 if t.is_simd() {
324 let e = t.simd_type(cx.tcx());
325 if !e.is_machine() {
326 cx.sess().fatal(&format!("monomorphising SIMD type `{}` with \
327 a non-machine element type `{}`",
328 t, e))
329 }
330 let llet = in_memory_type_of(cx, e);
c1a9b12d 331 let n = t.simd_size(cx.tcx()) as u64;
1a4d82fc
JJ
332 ensure_array_fits_in_address_space(cx, llet, n, t);
333 Type::vector(&llet, n)
334 } else {
335 // Only create the named struct, but don't fill it in. We fill it
336 // in *after* placing it into the type cache. This prevents
337 // infinite recursion with recursive struct types.
338 let repr = adt::represent_type(cx, t);
339 let tps = substs.types.get_slice(subst::TypeSpace);
e9174d1e 340 let name = llvm_type_name(cx, def.did, tps);
7453a54e 341 adt::incomplete_type_of(cx, &repr, &name[..])
1a4d82fc
JJ
342 }
343 }
344
5bcae85e
SL
345 ty::TyInfer(..) |
346 ty::TyProjection(..) |
347 ty::TyParam(..) |
348 ty::TyAnon(..) |
349 ty::TyError => bug!("type_of with {:?}", t),
1a4d82fc
JJ
350 };
351
54a0048b 352 debug!("--> mapped t={:?} to llty={:?}", t, llty);
1a4d82fc
JJ
353
354 cx.lltypes().borrow_mut().insert(t, llty);
355
356 // If this was an enum or struct, fill in the type now.
357 match t.sty {
62682a34 358 ty::TyEnum(..) | ty::TyStruct(..) | ty::TyClosure(..)
e9174d1e 359 if !t.is_simd() => {
1a4d82fc 360 let repr = adt::represent_type(cx, t);
7453a54e 361 adt::finish_type_of(cx, &repr, &mut llty);
1a4d82fc
JJ
362 }
363 _ => ()
364 }
365
c34b1796 366 llty
1a4d82fc
JJ
367}
368
369pub fn align_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>)
370 -> machine::llalign {
371 let llty = sizing_type_of(cx, t);
372 machine::llalign_of_min(cx, llty)
373}
374
c34b1796 375fn llvm_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
e9174d1e 376 did: DefId,
c34b1796
AL
377 tps: &[Ty<'tcx>])
378 -> String {
c1a9b12d 379 let base = cx.tcx().item_path_str(did);
62682a34 380 let strings: Vec<String> = tps.iter().map(|t| t.to_string()).collect();
1a4d82fc
JJ
381 let tstr = if strings.is_empty() {
382 base
383 } else {
c1a9b12d 384 format!("{}<{}>", base, strings.join(", "))
1a4d82fc
JJ
385 };
386
387 if did.krate == 0 {
c34b1796 388 tstr
1a4d82fc 389 } else {
c34b1796 390 format!("{}.{}", did.krate, tstr)
1a4d82fc
JJ
391 }
392}