]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/type_.rs
Rollup merge of #41249 - GuillaumeGomez:rustdoc-render, r=steveklabnik,frewsxcv
[rust.git] / src / librustc_trans / type_.rs
1 // Copyright 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_upper_case_globals)]
12
13 use llvm;
14 use llvm::{ContextRef, TypeRef, Bool, False, True, TypeKind};
15 use llvm::{Float, Double, X86_FP80, PPC_FP128, FP128};
16
17 use context::CrateContext;
18
19 use syntax::ast;
20 use rustc::ty::layout;
21
22 use std::ffi::CString;
23 use std::fmt;
24 use std::mem;
25 use std::ptr;
26
27 use libc::c_uint;
28
29 #[derive(Clone, Copy, PartialEq)]
30 #[repr(C)]
31 pub struct Type {
32     rf: TypeRef
33 }
34
35 impl fmt::Debug for Type {
36     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
37         f.write_str(&llvm::build_string(|s| unsafe {
38             llvm::LLVMRustWriteTypeToString(self.to_ref(), s);
39         }).expect("non-UTF8 type description from LLVM"))
40     }
41 }
42
43 macro_rules! ty {
44     ($e:expr) => ( Type::from_ref(unsafe { $e }))
45 }
46
47 /// Wrapper for LLVM TypeRef
48 impl Type {
49     #[inline(always)]
50     pub fn from_ref(r: TypeRef) -> Type {
51         Type {
52             rf: r
53         }
54     }
55
56     #[inline(always)] // So it doesn't kill --opt-level=0 builds of the compiler
57     pub fn to_ref(&self) -> TypeRef {
58         self.rf
59     }
60
61     pub fn to_ref_slice(slice: &[Type]) -> &[TypeRef] {
62         unsafe { mem::transmute(slice) }
63     }
64
65     pub fn void(ccx: &CrateContext) -> Type {
66         ty!(llvm::LLVMVoidTypeInContext(ccx.llcx()))
67     }
68
69     pub fn nil(ccx: &CrateContext) -> Type {
70         Type::empty_struct(ccx)
71     }
72
73     pub fn metadata(ccx: &CrateContext) -> Type {
74         ty!(llvm::LLVMRustMetadataTypeInContext(ccx.llcx()))
75     }
76
77     pub fn i1(ccx: &CrateContext) -> Type {
78         ty!(llvm::LLVMInt1TypeInContext(ccx.llcx()))
79     }
80
81     pub fn i8(ccx: &CrateContext) -> Type {
82         ty!(llvm::LLVMInt8TypeInContext(ccx.llcx()))
83     }
84
85     pub fn i8_llcx(llcx: ContextRef) -> Type {
86         ty!(llvm::LLVMInt8TypeInContext(llcx))
87     }
88
89     pub fn i16(ccx: &CrateContext) -> Type {
90         ty!(llvm::LLVMInt16TypeInContext(ccx.llcx()))
91     }
92
93     pub fn i32(ccx: &CrateContext) -> Type {
94         ty!(llvm::LLVMInt32TypeInContext(ccx.llcx()))
95     }
96
97     pub fn i64(ccx: &CrateContext) -> Type {
98         ty!(llvm::LLVMInt64TypeInContext(ccx.llcx()))
99     }
100
101     pub fn i128(ccx: &CrateContext) -> Type {
102         ty!(llvm::LLVMIntTypeInContext(ccx.llcx(), 128))
103     }
104
105     // Creates an integer type with the given number of bits, e.g. i24
106     pub fn ix(ccx: &CrateContext, num_bits: u64) -> Type {
107         ty!(llvm::LLVMIntTypeInContext(ccx.llcx(), num_bits as c_uint))
108     }
109
110     pub fn f32(ccx: &CrateContext) -> Type {
111         ty!(llvm::LLVMFloatTypeInContext(ccx.llcx()))
112     }
113
114     pub fn f64(ccx: &CrateContext) -> Type {
115         ty!(llvm::LLVMDoubleTypeInContext(ccx.llcx()))
116     }
117
118     pub fn bool(ccx: &CrateContext) -> Type {
119         Type::i8(ccx)
120     }
121
122     pub fn char(ccx: &CrateContext) -> Type {
123         Type::i32(ccx)
124     }
125
126     pub fn i8p(ccx: &CrateContext) -> Type {
127         Type::i8(ccx).ptr_to()
128     }
129
130     pub fn i8p_llcx(llcx: ContextRef) -> Type {
131         Type::i8_llcx(llcx).ptr_to()
132     }
133
134     pub fn int(ccx: &CrateContext) -> Type {
135         match &ccx.tcx().sess.target.target.target_pointer_width[..] {
136             "16" => Type::i16(ccx),
137             "32" => Type::i32(ccx),
138             "64" => Type::i64(ccx),
139             tws => bug!("Unsupported target word size for int: {}", tws),
140         }
141     }
142
143     pub fn int_from_ty(ccx: &CrateContext, t: ast::IntTy) -> Type {
144         match t {
145             ast::IntTy::Is => ccx.int_type(),
146             ast::IntTy::I8 => Type::i8(ccx),
147             ast::IntTy::I16 => Type::i16(ccx),
148             ast::IntTy::I32 => Type::i32(ccx),
149             ast::IntTy::I64 => Type::i64(ccx),
150             ast::IntTy::I128 => Type::i128(ccx),
151         }
152     }
153
154     pub fn uint_from_ty(ccx: &CrateContext, t: ast::UintTy) -> Type {
155         match t {
156             ast::UintTy::Us => ccx.int_type(),
157             ast::UintTy::U8 => Type::i8(ccx),
158             ast::UintTy::U16 => Type::i16(ccx),
159             ast::UintTy::U32 => Type::i32(ccx),
160             ast::UintTy::U64 => Type::i64(ccx),
161             ast::UintTy::U128 => Type::i128(ccx),
162         }
163     }
164
165     pub fn float_from_ty(ccx: &CrateContext, t: ast::FloatTy) -> Type {
166         match t {
167             ast::FloatTy::F32 => Type::f32(ccx),
168             ast::FloatTy::F64 => Type::f64(ccx),
169         }
170     }
171
172     pub fn func(args: &[Type], ret: &Type) -> Type {
173         let slice: &[TypeRef] = Type::to_ref_slice(args);
174         ty!(llvm::LLVMFunctionType(ret.to_ref(), slice.as_ptr(),
175                                    args.len() as c_uint, False))
176     }
177
178     pub fn variadic_func(args: &[Type], ret: &Type) -> Type {
179         let slice: &[TypeRef] = Type::to_ref_slice(args);
180         ty!(llvm::LLVMFunctionType(ret.to_ref(), slice.as_ptr(),
181                                    args.len() as c_uint, True))
182     }
183
184     pub fn struct_(ccx: &CrateContext, els: &[Type], packed: bool) -> Type {
185         let els: &[TypeRef] = Type::to_ref_slice(els);
186         ty!(llvm::LLVMStructTypeInContext(ccx.llcx(), els.as_ptr(),
187                                           els.len() as c_uint,
188                                           packed as Bool))
189     }
190
191     pub fn named_struct(ccx: &CrateContext, name: &str) -> Type {
192         let name = CString::new(name).unwrap();
193         ty!(llvm::LLVMStructCreateNamed(ccx.llcx(), name.as_ptr()))
194     }
195
196     pub fn empty_struct(ccx: &CrateContext) -> Type {
197         Type::struct_(ccx, &[], false)
198     }
199
200     pub fn array(ty: &Type, len: u64) -> Type {
201         ty!(llvm::LLVMRustArrayType(ty.to_ref(), len))
202     }
203
204     pub fn vector(ty: &Type, len: u64) -> Type {
205         ty!(llvm::LLVMVectorType(ty.to_ref(), len as c_uint))
206     }
207
208     pub fn vec(ccx: &CrateContext, ty: &Type) -> Type {
209         Type::struct_(ccx,
210             &[Type::array(ty, 0), Type::int(ccx)],
211         false)
212     }
213
214     pub fn opaque_vec(ccx: &CrateContext) -> Type {
215         Type::vec(ccx, &Type::i8(ccx))
216     }
217
218     pub fn vtable_ptr(ccx: &CrateContext) -> Type {
219         Type::func(&[Type::i8p(ccx)], &Type::void(ccx)).ptr_to().ptr_to()
220     }
221
222     pub fn kind(&self) -> TypeKind {
223         unsafe {
224             llvm::LLVMRustGetTypeKind(self.to_ref())
225         }
226     }
227
228     pub fn set_struct_body(&mut self, els: &[Type], packed: bool) {
229         let slice: &[TypeRef] = Type::to_ref_slice(els);
230         unsafe {
231             llvm::LLVMStructSetBody(self.to_ref(), slice.as_ptr(),
232                                     els.len() as c_uint, packed as Bool)
233         }
234     }
235
236     pub fn ptr_to(&self) -> Type {
237         ty!(llvm::LLVMPointerType(self.to_ref(), 0))
238     }
239
240     pub fn is_aggregate(&self) -> bool {
241         match self.kind() {
242             TypeKind::Struct | TypeKind::Array => true,
243             _ =>  false
244         }
245     }
246
247     pub fn is_packed(&self) -> bool {
248         unsafe {
249             llvm::LLVMIsPackedStruct(self.to_ref()) == True
250         }
251     }
252
253     pub fn element_type(&self) -> Type {
254         unsafe {
255             Type::from_ref(llvm::LLVMGetElementType(self.to_ref()))
256         }
257     }
258
259     /// Return the number of elements in `self` if it is a LLVM vector type.
260     pub fn vector_length(&self) -> usize {
261         unsafe {
262             llvm::LLVMGetVectorSize(self.to_ref()) as usize
263         }
264     }
265
266     pub fn array_length(&self) -> usize {
267         unsafe {
268             llvm::LLVMGetArrayLength(self.to_ref()) as usize
269         }
270     }
271
272     pub fn field_types(&self) -> Vec<Type> {
273         unsafe {
274             let n_elts = llvm::LLVMCountStructElementTypes(self.to_ref()) as usize;
275             if n_elts == 0 {
276                 return Vec::new();
277             }
278             let mut elts = vec![Type { rf: ptr::null_mut() }; n_elts];
279             llvm::LLVMGetStructElementTypes(self.to_ref(),
280                                             elts.as_mut_ptr() as *mut TypeRef);
281             elts
282         }
283     }
284
285     pub fn return_type(&self) -> Type {
286         ty!(llvm::LLVMGetReturnType(self.to_ref()))
287     }
288
289     pub fn func_params(&self) -> Vec<Type> {
290         unsafe {
291             let n_args = llvm::LLVMCountParamTypes(self.to_ref()) as usize;
292             let mut args = vec![Type { rf: ptr::null_mut() }; n_args];
293             llvm::LLVMGetParamTypes(self.to_ref(),
294                                     args.as_mut_ptr() as *mut TypeRef);
295             args
296         }
297     }
298
299     pub fn float_width(&self) -> usize {
300         match self.kind() {
301             Float => 32,
302             Double => 64,
303             X86_FP80 => 80,
304             FP128 | PPC_FP128 => 128,
305             _ => bug!("llvm_float_width called on a non-float type")
306         }
307     }
308
309     /// Retrieve the bit width of the integer type `self`.
310     pub fn int_width(&self) -> u64 {
311         unsafe {
312             llvm::LLVMGetIntTypeWidth(self.to_ref()) as u64
313         }
314     }
315
316     pub fn from_integer(cx: &CrateContext, i: layout::Integer) -> Type {
317         use rustc::ty::layout::Integer::*;
318         match i {
319             I1 => Type::i1(cx),
320             I8 => Type::i8(cx),
321             I16 => Type::i16(cx),
322             I32 => Type::i32(cx),
323             I64 => Type::i64(cx),
324             I128 => Type::i128(cx),
325         }
326     }
327
328     pub fn from_primitive(ccx: &CrateContext, p: layout::Primitive) -> Type {
329         match p {
330             layout::Int(i) => Type::from_integer(ccx, i),
331             layout::F32 => Type::f32(ccx),
332             layout::F64 => Type::f64(ccx),
333             layout::Pointer => bug!("It is not possible to convert Pointer directly to Type.")
334         }
335     }
336 }