]> git.proxmox.com Git - rustc.git/blob - src/librustc_trans/trans/type_of.rs
49601ac6fe94dd85e5f713beecc42aa9f07303d4
[rustc.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
20 use trans::type_::Type;
21
22 use syntax::abi;
23 use syntax::ast;
24
25 // LLVM doesn't like objects that are too big. Issue #17913
26 fn 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
37 pub fn arg_is_indirect<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
38 arg_ty: Ty<'tcx>) -> bool {
39 !type_is_immediate(ccx, arg_ty) && !type_is_fat_ptr(ccx.tcx(), arg_ty)
40 }
41
42 pub fn return_uses_outptr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
43 ty: Ty<'tcx>) -> bool {
44 arg_is_indirect(ccx, ty)
45 }
46
47 pub 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
57 /// Yields the types of the "real" arguments for this function. For most
58 /// functions, these are simply the types of the arguments. For functions with
59 /// the `RustCall` ABI, however, this untuples the arguments of the function.
60 pub fn untuple_arguments_if_necessary<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
61 inputs: &[Ty<'tcx>],
62 abi: abi::Abi)
63 -> Vec<Ty<'tcx>> {
64 if abi != abi::RustCall {
65 return inputs.iter().cloned().collect()
66 }
67
68 if inputs.is_empty() {
69 return Vec::new()
70 }
71
72 let mut result = Vec::new();
73 for (i, &arg_prior_to_tuple) in inputs.iter().enumerate() {
74 if i < inputs.len() - 1 {
75 result.push(arg_prior_to_tuple);
76 }
77 }
78
79 match inputs[inputs.len() - 1].sty {
80 ty::TyTuple(ref tupled_arguments) => {
81 debug!("untuple_arguments_if_necessary(): untupling arguments");
82 for &tupled_argument in tupled_arguments {
83 result.push(tupled_argument);
84 }
85 }
86 _ => {
87 ccx.tcx().sess.bug("argument to function with \"rust-call\" ABI \
88 is neither a tuple nor unit")
89 }
90 }
91
92 result
93 }
94
95 pub fn type_of_rust_fn<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
96 llenvironment_type: Option<Type>,
97 sig: &ty::Binder<ty::FnSig<'tcx>>,
98 abi: abi::Abi)
99 -> Type
100 {
101 debug!("type_of_rust_fn(sig={:?},abi={:?})",
102 sig,
103 abi);
104
105 let sig = ty::erase_late_bound_regions(cx.tcx(), sig);
106 assert!(!sig.variadic); // rust fns are never variadic
107
108 let mut atys: Vec<Type> = Vec::new();
109
110 // First, munge the inputs, if this has the `rust-call` ABI.
111 let inputs = untuple_arguments_if_necessary(cx, &sig.inputs, abi);
112
113 // Arg 0: Output pointer.
114 // (if the output type is non-immediate)
115 let lloutputtype = match sig.output {
116 ty::FnConverging(output) => {
117 let use_out_pointer = return_uses_outptr(cx, output);
118 let lloutputtype = arg_type_of(cx, output);
119 // Use the output as the actual return value if it's immediate.
120 if use_out_pointer {
121 atys.push(lloutputtype.ptr_to());
122 Type::void(cx)
123 } else if return_type_is_void(cx, output) {
124 Type::void(cx)
125 } else {
126 lloutputtype
127 }
128 }
129 ty::FnDiverging => Type::void(cx)
130 };
131
132 // Arg 1: Environment
133 match llenvironment_type {
134 None => {}
135 Some(llenvironment_type) => atys.push(llenvironment_type),
136 }
137
138 // ... then explicit args.
139 for input in &inputs {
140 let arg_ty = type_of_explicit_arg(cx, input);
141
142 if type_is_fat_ptr(cx.tcx(), input) {
143 atys.extend(arg_ty.field_types());
144 } else {
145 atys.push(arg_ty);
146 }
147 }
148
149 Type::func(&atys[..], &lloutputtype)
150 }
151
152 // Given a function type and a count of ty params, construct an llvm type
153 pub fn type_of_fn_from_ty<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fty: Ty<'tcx>) -> Type {
154 match fty.sty {
155 ty::TyBareFn(_, ref f) => {
156 // FIXME(#19925) once fn item types are
157 // zero-sized, we'll need to do something here
158 if f.abi == abi::Rust || f.abi == abi::RustCall {
159 type_of_rust_fn(cx, None, &f.sig, f.abi)
160 } else {
161 foreign::lltype_for_foreign_fn(cx, fty)
162 }
163 }
164 _ => {
165 cx.sess().bug("type_of_fn_from_ty given non-closure, non-bare-fn")
166 }
167 }
168 }
169
170 // A "sizing type" is an LLVM type, the size and alignment of which are
171 // guaranteed to be equivalent to what you would get out of `type_of()`. It's
172 // useful because:
173 //
174 // (1) It may be cheaper to compute the sizing type than the full type if all
175 // you're interested in is the size and/or alignment;
176 //
177 // (2) It won't make any recursive calls to determine the structure of the
178 // type behind pointers. This can help prevent infinite loops for
179 // recursive types. For example, enum types rely on this behavior.
180
181 pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
182 match cx.llsizingtypes().borrow().get(&t).cloned() {
183 Some(t) => return t,
184 None => ()
185 }
186
187 let llsizingty = match t.sty {
188 _ if !type_is_sized(cx.tcx(), t) => {
189 Type::struct_(cx, &[Type::i8p(cx), Type::i8p(cx)], false)
190 }
191
192 ty::TyBool => Type::bool(cx),
193 ty::TyChar => Type::char(cx),
194 ty::TyInt(t) => Type::int_from_ty(cx, t),
195 ty::TyUint(t) => Type::uint_from_ty(cx, t),
196 ty::TyFloat(t) => Type::float_from_ty(cx, t),
197
198 ty::TyBox(ty) | ty::TyRef(_, ty::mt{ty, ..}) | ty::TyRawPtr(ty::mt{ty, ..}) => {
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
206 ty::TyBareFn(..) => Type::i8p(cx),
207
208 ty::TyArray(ty, size) => {
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
215 ty::TyTuple(ref tys) if tys.is_empty() => {
216 Type::nil(cx)
217 }
218
219 ty::TyTuple(..) | ty::TyEnum(..) | ty::TyClosure(..) => {
220 let repr = adt::represent_type(cx, t);
221 adt::sizing_type_of(cx, &*repr, false)
222 }
223
224 ty::TyStruct(..) => {
225 if ty::type_is_simd(cx.tcx(), t) {
226 let llet = type_of(cx, ty::simd_type(cx.tcx(), t));
227 let n = ty::simd_size(cx.tcx(), t) as u64;
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
236 ty::TyProjection(..) | ty::TyInfer(..) | ty::TyParam(..) | ty::TyError(..) => {
237 cx.sess().bug(&format!("fictitious type {:?} in sizing_type_of()",
238 t))
239 }
240 ty::TySlice(_) | ty::TyTrait(..) | ty::TyStr => unreachable!()
241 };
242
243 cx.llsizingtypes().borrow_mut().insert(t, llsizingty);
244 llsizingty
245 }
246
247 pub fn foreign_arg_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
248 if ty::type_is_bool(t) {
249 Type::i1(cx)
250 } else {
251 type_of(cx, t)
252 }
253 }
254
255 pub fn arg_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
256 if ty::type_is_bool(t) {
257 Type::i1(cx)
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 }
265 } else {
266 type_of(cx, t)
267 }
268 }
269
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`.
279 pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, ty: Ty<'tcx>) -> Type {
280 let ty = if !type_is_sized(cx.tcx(), ty) {
281 ty::mk_imm_ptr(cx.tcx(), ty)
282 } else {
283 ty
284 };
285 in_memory_type_of(cx, ty)
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 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.
300 pub fn in_memory_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
301 // Check the cache.
302 match cx.lltypes().borrow().get(&t) {
303 Some(&llty) => return llty,
304 None => ()
305 }
306
307 debug!("type_of {:?}", t);
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 {
319 let llty = in_memory_type_of(cx, t_norm);
320 debug!("--> normalized {:?} {:?} to {:?} {:?} llty={}",
321 t,
322 t,
323 t_norm,
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 {
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) => {
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);
343 let name = llvm_type_name(cx, did, tps);
344 adt::incomplete_type_of(cx, &*repr, &name[..])
345 }
346 ty::TyClosure(..) => {
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
354 adt::incomplete_type_of(cx, &*repr, "closure")
355 }
356
357 ty::TyBox(ty) | ty::TyRef(_, ty::mt{ty, ..}) | ty::TyRawPtr(ty::mt{ty, ..}) => {
358 if !type_is_sized(cx.tcx(), ty) {
359 if let ty::TyStr = ty.sty {
360 // This means we get a nicer name in the output (str is always
361 // unsized).
362 cx.tn().find_type("str_slice").unwrap()
363 } else {
364 let ptr_ty = in_memory_type_of(cx, ty).ptr_to();
365 let unsized_part = ty::struct_tail(cx.tcx(), ty);
366 let info_ty = match unsized_part.sty {
367 ty::TyStr | ty::TyArray(..) | ty::TySlice(_) => {
368 Type::uint_from_ty(cx, ast::TyUs)
369 }
370 ty::TyTrait(_) => Type::vtable_ptr(cx),
371 _ => panic!("Unexpected type returned from \
372 struct_tail: {:?} for ty={:?}",
373 unsized_part, ty)
374 };
375 Type::struct_(cx, &[ptr_ty, info_ty], false)
376 }
377 } else {
378 in_memory_type_of(cx, ty).ptr_to()
379 }
380 }
381
382 ty::TyArray(ty, size) => {
383 let size = size as u64;
384 let llty = in_memory_type_of(cx, ty);
385 ensure_array_fits_in_address_space(cx, llty, size, t);
386 Type::array(&llty, size)
387 }
388
389 // Unsized slice types (and str) have the type of their element, and
390 // traits have the type of u8. This is so that the data pointer inside
391 // fat pointers is of the right type (e.g. for array accesses), even
392 // when taking the address of an unsized field in a struct.
393 ty::TySlice(ty) => in_memory_type_of(cx, ty),
394 ty::TyStr | ty::TyTrait(..) => Type::i8(cx),
395
396 ty::TyBareFn(..) => {
397 type_of_fn_from_ty(cx, t).ptr_to()
398 }
399 ty::TyTuple(ref tys) if tys.is_empty() => Type::nil(cx),
400 ty::TyTuple(..) => {
401 let repr = adt::represent_type(cx, t);
402 adt::type_of(cx, &*repr)
403 }
404 ty::TyStruct(did, ref substs) => {
405 if ty::type_is_simd(cx.tcx(), t) {
406 let llet = in_memory_type_of(cx, ty::simd_type(cx.tcx(), t));
407 let n = ty::simd_size(cx.tcx(), t) as u64;
408 ensure_array_fits_in_address_space(cx, llet, n, t);
409 Type::vector(&llet, n)
410 } else {
411 // Only create the named struct, but don't fill it in. We fill it
412 // in *after* placing it into the type cache. This prevents
413 // infinite recursion with recursive struct types.
414 let repr = adt::represent_type(cx, t);
415 let tps = substs.types.get_slice(subst::TypeSpace);
416 let name = llvm_type_name(cx, did, tps);
417 adt::incomplete_type_of(cx, &*repr, &name[..])
418 }
419 }
420
421 ty::TyInfer(..) => cx.sess().bug("type_of with TyInfer"),
422 ty::TyProjection(..) => cx.sess().bug("type_of with TyProjection"),
423 ty::TyParam(..) => cx.sess().bug("type_of with ty_param"),
424 ty::TyError(..) => cx.sess().bug("type_of with TyError"),
425 };
426
427 debug!("--> mapped t={:?} {:?} to llty={}",
428 t,
429 t,
430 cx.tn().type_to_string(llty));
431
432 cx.lltypes().borrow_mut().insert(t, llty);
433
434 // If this was an enum or struct, fill in the type now.
435 match t.sty {
436 ty::TyEnum(..) | ty::TyStruct(..) | ty::TyClosure(..)
437 if !ty::type_is_simd(cx.tcx(), t) => {
438 let repr = adt::represent_type(cx, t);
439 adt::finish_type_of(cx, &*repr, &mut llty);
440 }
441 _ => ()
442 }
443
444 llty
445 }
446
447 pub fn align_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>)
448 -> machine::llalign {
449 let llty = sizing_type_of(cx, t);
450 machine::llalign_of_min(cx, llty)
451 }
452
453 fn llvm_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
454 did: ast::DefId,
455 tps: &[Ty<'tcx>])
456 -> String {
457 let base = ty::item_path_str(cx.tcx(), did);
458 let strings: Vec<String> = tps.iter().map(|t| t.to_string()).collect();
459 let tstr = if strings.is_empty() {
460 base
461 } else {
462 format!("{}<{}>", base, strings.connect(", "))
463 };
464
465 if did.krate == 0 {
466 tstr
467 } else {
468 format!("{}.{}", did.krate, tstr)
469 }
470 }
471
472 pub fn type_of_dtor<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, self_ty: Ty<'tcx>) -> Type {
473 let self_ty = type_of(ccx, self_ty).ptr_to();
474 Type::func(&[self_ty], &Type::void(ccx))
475 }