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.
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.
11 #![allow(non_camel_case_types)]
13 pub use self::named_ty::*;
20 use middle::ty::{self, RegionEscape, Ty};
22 use util::ppaux::Repr;
24 use trans::type_::Type;
30 // LLVM doesn't like objects that are too big. Issue #17913
31 fn ensure_array_fits_in_address_space<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
33 size: machine::llsize,
34 scapegoat: Ty<'tcx>) {
35 let esz = machine::llsize_of_alloc(ccx, llet);
36 match esz.checked_mul(size) {
37 Some(n) if n < ccx.obj_size_bound() => {}
38 _ => { ccx.report_overbig_object(scapegoat) }
42 pub fn arg_is_indirect<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
43 arg_ty: Ty<'tcx>) -> bool {
44 !type_is_immediate(ccx, arg_ty)
47 pub fn return_uses_outptr<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
48 ty: Ty<'tcx>) -> bool {
49 !type_is_immediate(ccx, ty)
52 pub fn type_of_explicit_arg<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
53 arg_ty: Ty<'tcx>) -> Type {
54 let llty = arg_type_of(ccx, arg_ty);
55 if arg_is_indirect(ccx, arg_ty) {
62 /// Yields the types of the "real" arguments for this function. For most
63 /// functions, these are simply the types of the arguments. For functions with
64 /// the `RustCall` ABI, however, this untuples the arguments of the function.
65 pub fn untuple_arguments_if_necessary<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
69 if abi != abi::RustCall {
70 return inputs.iter().cloned().collect()
73 if inputs.len() == 0 {
77 let mut result = Vec::new();
78 for (i, &arg_prior_to_tuple) in inputs.iter().enumerate() {
79 if i < inputs.len() - 1 {
80 result.push(arg_prior_to_tuple);
84 match inputs[inputs.len() - 1].sty {
85 ty::ty_tup(ref tupled_arguments) => {
86 debug!("untuple_arguments_if_necessary(): untupling arguments");
87 for &tupled_argument in tupled_arguments {
88 result.push(tupled_argument);
92 ccx.tcx().sess.bug("argument to function with \"rust-call\" ABI \
93 is neither a tuple nor unit")
100 pub fn type_of_rust_fn<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
101 llenvironment_type: Option<Type>,
102 sig: &ty::Binder<ty::FnSig<'tcx>>,
106 debug!("type_of_rust_fn(sig={},abi={:?})",
110 let sig = ty::erase_late_bound_regions(cx.tcx(), sig);
111 assert!(!sig.variadic); // rust fns are never variadic
113 let mut atys: Vec<Type> = Vec::new();
115 // First, munge the inputs, if this has the `rust-call` ABI.
116 let inputs = untuple_arguments_if_necessary(cx, &sig.inputs, abi);
118 // Arg 0: Output pointer.
119 // (if the output type is non-immediate)
120 let lloutputtype = match sig.output {
121 ty::FnConverging(output) => {
122 let use_out_pointer = return_uses_outptr(cx, output);
123 let lloutputtype = arg_type_of(cx, output);
124 // Use the output as the actual return value if it's immediate.
126 atys.push(lloutputtype.ptr_to());
128 } else if return_type_is_void(cx, output) {
134 ty::FnDiverging => Type::void(cx)
137 // Arg 1: Environment
138 match llenvironment_type {
140 Some(llenvironment_type) => atys.push(llenvironment_type),
143 // ... then explicit args.
144 let input_tys = inputs.iter().map(|&arg_ty| type_of_explicit_arg(cx, arg_ty));
145 atys.extend(input_tys);
147 Type::func(&atys[..], &lloutputtype)
150 // Given a function type and a count of ty params, construct an llvm type
151 pub fn type_of_fn_from_ty<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, fty: Ty<'tcx>) -> Type {
153 ty::ty_bare_fn(_, ref f) => {
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)
159 foreign::lltype_for_foreign_fn(cx, fty)
163 cx.sess().bug("type_of_fn_from_ty given non-closure, non-bare-fn")
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
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;
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.
179 pub fn sizing_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
180 match cx.llsizingtypes().borrow().get(&t).cloned() {
185 let llsizingty = match t.sty {
186 _ if !lltype_is_sized(cx.tcx(), t) => {
187 cx.sess().bug(&format!("trying to take the sizing type of {}, an unsized type",
188 ppaux::ty_to_string(cx.tcx(), t))[])
191 ty::ty_bool => Type::bool(cx),
192 ty::ty_char => Type::char(cx),
193 ty::ty_int(t) => Type::int_from_ty(cx, t),
194 ty::ty_uint(t) => Type::uint_from_ty(cx, t),
195 ty::ty_float(t) => Type::float_from_ty(cx, t),
197 ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) | ty::ty_ptr(ty::mt{ty, ..}) => {
198 if type_is_sized(cx.tcx(), ty) {
201 Type::struct_(cx, &[Type::i8p(cx), Type::i8p(cx)], false)
205 ty::ty_bare_fn(..) => Type::i8p(cx),
207 ty::ty_vec(ty, Some(size)) => {
208 let llty = sizing_type_of(cx, ty);
209 let size = size as u64;
210 ensure_array_fits_in_address_space(cx, llty, size, t);
211 Type::array(&llty, size)
214 ty::ty_tup(ref tys) if tys.is_empty() => {
218 ty::ty_tup(..) | ty::ty_enum(..) | ty::ty_closure(..) => {
219 let repr = adt::represent_type(cx, t);
220 adt::sizing_type_of(cx, &*repr, false)
223 ty::ty_struct(..) => {
224 if ty::type_is_simd(cx.tcx(), t) {
225 let llet = type_of(cx, ty::simd_type(cx.tcx(), t));
226 let n = ty::simd_size(cx.tcx(), t) as u64;
227 ensure_array_fits_in_address_space(cx, llet, n, t);
228 Type::vector(&llet, n)
230 let repr = adt::represent_type(cx, t);
231 adt::sizing_type_of(cx, &*repr, false)
236 Type::struct_(cx, &[Type::i8p(cx), Type::i8p(cx)], false)
239 ty::ty_projection(..) | ty::ty_infer(..) | ty::ty_param(..) | ty::ty_err(..) => {
240 cx.sess().bug(&format!("fictitious type {} in sizing_type_of()",
241 ppaux::ty_to_string(cx.tcx(), t))[])
243 ty::ty_vec(_, None) | ty::ty_trait(..) | ty::ty_str => panic!("unreachable")
246 cx.llsizingtypes().borrow_mut().insert(t, llsizingty);
250 pub fn foreign_arg_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
251 if ty::type_is_bool(t) {
258 pub fn arg_type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
259 if ty::type_is_bool(t) {
261 } else if type_is_immediate(cx, t) && type_of(cx, t).is_aggregate() {
262 // We want to pass small aggregates as immediate values, but using an aggregate LLVM type
263 // for this leads to bad optimizations, so its arg type is an appropriately sized integer
264 match machine::llsize_of_alloc(cx, sizing_type_of(cx, t)) {
266 n => Type::ix(cx, n * 8),
273 // NB: If you update this, be sure to update `sizing_type_of()` as well.
274 pub fn type_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
275 fn type_of_unsize_info<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>) -> Type {
276 // It is possible to end up here with a sized type. This happens with a
277 // struct which might be unsized, but is monomorphised to a sized type.
278 // In this case we'll fake a fat pointer with no unsize info (we use 0).
279 // However, its still a fat pointer, so we need some type use.
280 if type_is_sized(cx.tcx(), t) {
281 return Type::i8p(cx);
284 match unsized_part_of_type(cx.tcx(), t).sty {
285 ty::ty_str | ty::ty_vec(..) => Type::uint_from_ty(cx, ast::TyUs(false)),
286 ty::ty_trait(_) => Type::vtable_ptr(cx),
287 _ => panic!("Unexpected type returned from unsized_part_of_type : {}",
293 match cx.lltypes().borrow().get(&t) {
294 Some(&llty) => return llty,
298 debug!("type_of {} {:?}", t.repr(cx.tcx()), t.sty);
300 assert!(!t.has_escaping_regions());
302 // Replace any typedef'd types with their equivalent non-typedef
303 // type. This ensures that all LLVM nominal types that contain
304 // Rust types are defined as the same LLVM types. If we don't do
305 // this then, e.g. `Option<{myfield: bool}>` would be a different
306 // type than `Option<myrec>`.
307 let t_norm = erase_regions(cx.tcx(), &t);
310 let llty = type_of(cx, t_norm);
311 debug!("--> normalized {} {:?} to {} {:?} llty={}",
314 t_norm.repr(cx.tcx()),
316 cx.tn().type_to_string(llty));
317 cx.lltypes().borrow_mut().insert(t, llty);
321 let mut llty = match t.sty {
322 ty::ty_bool => Type::bool(cx),
323 ty::ty_char => Type::char(cx),
324 ty::ty_int(t) => Type::int_from_ty(cx, t),
325 ty::ty_uint(t) => Type::uint_from_ty(cx, t),
326 ty::ty_float(t) => Type::float_from_ty(cx, t),
327 ty::ty_enum(did, ref substs) => {
328 // Only create the named struct, but don't fill it in. We
329 // fill it in *after* placing it into the type cache. This
330 // avoids creating more than one copy of the enum when one
331 // of the enum's variants refers to the enum itself.
332 let repr = adt::represent_type(cx, t);
333 let tps = substs.types.get_slice(subst::TypeSpace);
334 let name = llvm_type_name(cx, an_enum, did, tps);
335 adt::incomplete_type_of(cx, &*repr, &name[..])
337 ty::ty_closure(did, _, ref substs) => {
338 // Only create the named struct, but don't fill it in. We
339 // fill it in *after* placing it into the type cache.
340 let repr = adt::represent_type(cx, t);
341 // Unboxed closures can have substitutions in all spaces
342 // inherited from their environment, so we use entire
343 // contents of the VecPerParamSpace to to construct the llvm
345 let name = llvm_type_name(cx, a_closure, did, substs.types.as_slice());
346 adt::incomplete_type_of(cx, &*repr, &name[..])
349 ty::ty_uniq(ty) | ty::ty_rptr(_, ty::mt{ty, ..}) | ty::ty_ptr(ty::mt{ty, ..}) => {
352 // This means we get a nicer name in the output (str is always
354 cx.tn().find_type("str_slice").unwrap()
356 ty::ty_trait(..) => Type::opaque_trait(cx),
357 _ if !type_is_sized(cx.tcx(), ty) => {
358 let p_ty = type_of(cx, ty).ptr_to();
359 Type::struct_(cx, &[p_ty, type_of_unsize_info(cx, ty)], false)
361 _ => type_of(cx, ty).ptr_to(),
365 ty::ty_vec(ty, Some(size)) => {
366 let size = size as u64;
367 let llty = type_of(cx, ty);
368 ensure_array_fits_in_address_space(cx, llty, size, t);
369 Type::array(&llty, size)
371 ty::ty_vec(ty, None) => {
375 ty::ty_trait(..) => {
376 Type::opaque_trait_data(cx)
379 ty::ty_str => Type::i8(cx),
381 ty::ty_bare_fn(..) => {
382 type_of_fn_from_ty(cx, t).ptr_to()
384 ty::ty_tup(ref tys) if tys.is_empty() => Type::nil(cx),
386 let repr = adt::represent_type(cx, t);
387 adt::type_of(cx, &*repr)
389 ty::ty_struct(did, ref substs) => {
390 if ty::type_is_simd(cx.tcx(), t) {
391 let llet = type_of(cx, ty::simd_type(cx.tcx(), t));
392 let n = ty::simd_size(cx.tcx(), t) as u64;
393 ensure_array_fits_in_address_space(cx, llet, n, t);
394 Type::vector(&llet, n)
396 // Only create the named struct, but don't fill it in. We fill it
397 // in *after* placing it into the type cache. This prevents
398 // infinite recursion with recursive struct types.
399 let repr = adt::represent_type(cx, t);
400 let tps = substs.types.get_slice(subst::TypeSpace);
401 let name = llvm_type_name(cx, a_struct, did, tps);
402 adt::incomplete_type_of(cx, &*repr, &name[..])
406 ty::ty_open(t) => match t.sty {
407 ty::ty_struct(..) => {
408 let p_ty = type_of(cx, t).ptr_to();
409 Type::struct_(cx, &[p_ty, type_of_unsize_info(cx, t)], false)
411 ty::ty_vec(ty, None) => {
412 let p_ty = type_of(cx, ty).ptr_to();
413 Type::struct_(cx, &[p_ty, type_of_unsize_info(cx, t)], false)
416 let p_ty = Type::i8p(cx);
417 Type::struct_(cx, &[p_ty, type_of_unsize_info(cx, t)], false)
419 ty::ty_trait(..) => Type::opaque_trait(cx),
420 _ => cx.sess().bug(&format!("ty_open with sized type: {}",
421 ppaux::ty_to_string(cx.tcx(), t))[])
424 ty::ty_infer(..) => cx.sess().bug("type_of with ty_infer"),
425 ty::ty_projection(..) => cx.sess().bug("type_of with ty_projection"),
426 ty::ty_param(..) => cx.sess().bug("type_of with ty_param"),
427 ty::ty_err(..) => cx.sess().bug("type_of with ty_err"),
430 debug!("--> mapped t={} {:?} to llty={}",
433 cx.tn().type_to_string(llty));
435 cx.lltypes().borrow_mut().insert(t, llty);
437 // If this was an enum or struct, fill in the type now.
439 ty::ty_enum(..) | ty::ty_struct(..) | ty::ty_closure(..)
440 if !ty::type_is_simd(cx.tcx(), t) => {
441 let repr = adt::represent_type(cx, t);
442 adt::finish_type_of(cx, &*repr, &mut llty);
450 pub fn align_of<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>, t: Ty<'tcx>)
451 -> machine::llalign {
452 let llty = sizing_type_of(cx, t);
453 machine::llalign_of_min(cx, llty)
456 // Want refinements! (Or case classes, I guess
464 pub fn llvm_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
469 let name = match what {
470 a_struct => "struct",
472 a_closure => return "closure".to_string(),
475 let base = ty::item_path_str(cx.tcx(), did);
476 let strings: Vec<String> = tps.iter().map(|t| t.repr(cx.tcx())).collect();
477 let tstr = if strings.is_empty() {
480 format!("{}<{:?}>", base, strings)
484 format!("{}.{}", name, tstr)
486 format!("{}.{}[{}{}]", name, tstr, "#", did.krate)
490 pub fn type_of_dtor<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, self_ty: Ty<'tcx>) -> Type {
491 let self_ty = type_of(ccx, self_ty).ptr_to();
492 Type::func(&[self_ty], &Type::void(ccx))