Skip to main content

inkwell/types/
fn_type.rs

1use llvm_sys::core::{
2    LLVMCountParamTypes, LLVMGetParamTypes, LLVMGetReturnType, LLVMGetTypeKind, LLVMIsFunctionVarArg,
3};
4use llvm_sys::prelude::LLVMTypeRef;
5use llvm_sys::LLVMTypeKind;
6
7use std::fmt::{self, Display};
8use std::mem::forget;
9
10use crate::context::ContextRef;
11use crate::support::LLVMString;
12use crate::types::traits::AsTypeRef;
13use crate::types::{AnyType, BasicMetadataTypeEnum, BasicTypeEnum, PointerType, Type};
14use crate::AddressSpace;
15
16/// A `FunctionType` is the type of a function variable.
17#[derive(PartialEq, Eq, Clone, Copy)]
18pub struct FunctionType<'ctx> {
19    fn_type: Type<'ctx>,
20}
21
22impl<'ctx> FunctionType<'ctx> {
23    /// Create `FunctionType` from [`LLVMTypeRef`]
24    ///
25    /// # Safety
26    /// Undefined behavior, if referenced type isn't function type
27    pub unsafe fn new(fn_type: LLVMTypeRef) -> Self {
28        assert!(!fn_type.is_null());
29
30        FunctionType {
31            fn_type: Type::new(fn_type),
32        }
33    }
34
35    /// Creates a `PointerType` with this `FunctionType` for its element type.
36    ///
37    /// # Example
38    ///
39    /// ```no_run
40    /// use inkwell::context::Context;
41    /// use inkwell::AddressSpace;
42    ///
43    /// let context = Context::create();
44    /// let f32_type = context.f32_type();
45    /// let fn_type = f32_type.fn_type(&[], false);
46    /// let fn_ptr_type = fn_type.ptr_type(AddressSpace::default());
47    ///
48    /// #[cfg(feature = "typed-pointers")]
49    /// assert_eq!(fn_ptr_type.get_element_type().into_function_type(), fn_type);
50    /// ```
51    #[cfg_attr(
52        any(
53            all(feature = "llvm15-0", not(feature = "typed-pointers")),
54            all(feature = "llvm16-0", not(feature = "typed-pointers")),
55            feature = "llvm17-0",
56            feature = "llvm18-1",
57            feature = "llvm19-1",
58            feature = "llvm20-1",
59            feature = "llvm21-1",
60        ),
61        deprecated(
62            note = "Starting from version 15.0, LLVM doesn't differentiate between pointer types. Use Context::ptr_type instead."
63        )
64    )]
65    pub fn ptr_type(self, address_space: AddressSpace) -> PointerType<'ctx> {
66        self.fn_type.ptr_type(address_space)
67    }
68
69    /// Determines whether or not a `FunctionType` is a variadic function.
70    ///
71    /// # Example
72    ///
73    /// ```no_run
74    /// use inkwell::context::Context;
75    ///
76    /// let context = Context::create();
77    /// let f32_type = context.f32_type();
78    /// let fn_type = f32_type.fn_type(&[], true);
79    ///
80    /// assert!(fn_type.is_var_arg());
81    /// ```
82    pub fn is_var_arg(self) -> bool {
83        unsafe { LLVMIsFunctionVarArg(self.as_type_ref()) != 0 }
84    }
85
86    /// Gets param types this `FunctionType` has.
87    ///
88    /// # Example
89    ///
90    /// ```
91    /// use inkwell::context::Context;
92    ///
93    /// let context = Context::create();
94    /// let f32_type = context.f32_type();
95    /// let fn_type = f32_type.fn_type(&[f32_type.into()], true);
96    /// let param_types = fn_type.get_param_types();
97    ///
98    /// assert_eq!(param_types.len(), 1);
99    /// assert_eq!(param_types[0].into_float_type(), f32_type);
100    /// ```
101    pub fn get_param_types(self) -> Vec<BasicMetadataTypeEnum<'ctx>> {
102        let count = self.count_param_types();
103        let mut raw_vec: Vec<LLVMTypeRef> = Vec::with_capacity(count as usize);
104        let ptr = raw_vec.as_mut_ptr();
105
106        forget(raw_vec);
107
108        let raw_vec = unsafe {
109            LLVMGetParamTypes(self.as_type_ref(), ptr);
110
111            Vec::from_raw_parts(ptr, count as usize, count as usize)
112        };
113
114        raw_vec
115            .iter()
116            .map(|val| unsafe { BasicMetadataTypeEnum::new(*val) })
117            .collect()
118    }
119
120    /// Counts the number of param types this `FunctionType` has.
121    ///
122    /// # Example
123    ///
124    /// ```no_run
125    /// use inkwell::context::Context;
126    ///
127    /// let context = Context::create();
128    /// let f32_type = context.f32_type();
129    /// let fn_type = f32_type.fn_type(&[f32_type.into()], true);
130    ///
131    /// assert_eq!(fn_type.count_param_types(), 1);
132    /// ```
133    pub fn count_param_types(self) -> u32 {
134        unsafe { LLVMCountParamTypes(self.as_type_ref()) }
135    }
136
137    // REVIEW: Always false -> const fn?
138    /// Gets whether or not this `FunctionType` is sized or not. This is likely
139    /// always false and may be removed in the future.
140    ///
141    /// # Example
142    ///
143    /// ```no_run
144    /// use inkwell::context::Context;
145    ///
146    /// let context = Context::create();
147    /// let f32_type = context.f32_type();
148    /// let fn_type = f32_type.fn_type(&[], true);
149    ///
150    /// assert!(!fn_type.is_sized());
151    /// ```
152    pub fn is_sized(self) -> bool {
153        self.fn_type.is_sized()
154    }
155
156    // REVIEW: Does this work on functions?
157    // fn get_alignment(&self) -> IntValue {
158    //     self.fn_type.get_alignment()
159    // }
160
161    /// Gets a reference to the `Context` this `FunctionType` was created in.
162    ///
163    /// # Example
164    ///
165    /// ```no_run
166    /// use inkwell::context::Context;
167    ///
168    /// let context = Context::create();
169    /// let f32_type = context.f32_type();
170    /// let fn_type = f32_type.fn_type(&[], true);
171    ///
172    /// assert_eq!(fn_type.get_context(), context);
173    /// ```
174    pub fn get_context(self) -> ContextRef<'ctx> {
175        self.fn_type.get_context()
176    }
177
178    /// Print the definition of a `FunctionType` to `LLVMString`.
179    pub fn print_to_string(self) -> LLVMString {
180        self.fn_type.print_to_string()
181    }
182
183    /// Gets the return type of this `FunctionType`.
184    ///
185    /// # Example
186    ///
187    /// ```no_run
188    /// use inkwell::context::Context;
189    ///
190    /// let context = Context::create();
191    /// let f32_type = context.f32_type();
192    /// let fn_type = f32_type.fn_type(&[], true);
193    ///
194    /// assert_eq!(fn_type.get_return_type().unwrap().into_float_type(), f32_type);
195    /// ```
196    pub fn get_return_type(self) -> Option<BasicTypeEnum<'ctx>> {
197        let ty = unsafe { LLVMGetReturnType(self.as_type_ref()) };
198
199        let kind = unsafe { LLVMGetTypeKind(ty) };
200
201        if let LLVMTypeKind::LLVMVoidTypeKind = kind {
202            return None;
203        }
204
205        unsafe { Some(BasicTypeEnum::new(ty)) }
206    }
207
208    // REVIEW: Can you do undef for functions?
209    // Seems to "work" - no UB or SF so far but fails
210    // LLVMIsAFunction() check. Commenting out for further research
211    // pub fn get_undef(&self) -> FunctionValue {
212    //     FunctionValue::new(self.fn_type.get_undef()).expect("Should always get an undef value")
213    // }
214}
215
216impl fmt::Debug for FunctionType<'_> {
217    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
218        let llvm_type = self.print_to_string();
219
220        f.debug_struct("FunctionType")
221            .field("address", &self.as_type_ref())
222            .field("is_var_args", &self.is_var_arg())
223            .field("llvm_type", &llvm_type)
224            .finish()
225    }
226}
227
228unsafe impl AsTypeRef for FunctionType<'_> {
229    fn as_type_ref(&self) -> LLVMTypeRef {
230        self.fn_type.ty
231    }
232}
233
234impl Display for FunctionType<'_> {
235    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
236        write!(f, "{}", self.print_to_string())
237    }
238}