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