Getting a function type from a function value with opaque pointers

I’m struggling to update some code that uses the C API and tries to get the function type from a function value.

In fact we use the C API from rust, but that should not make much of a difference. The current (llvm 14) definition is (roughly)

#[derive(PartialEq, Eq, Clone, Copy, Hash)]
struct Value<'ctx> {
    value: LLVMValueRef,
    _marker: PhantomData<&'ctx ()>,
}

#[derive(PartialEq, Eq, Clone, Copy, Hash)]
pub struct FunctionValue<'ctx> {
    fn_value: Value<'ctx>,
}

pub fn get_type(self: FunctionValue<'ctx>) -> FunctionType<'ctx> {
    // use the FunctionValue as an LLVMValueRef, and get its type. Apparently this is a pointer type
    let ptr_type = unsafe { PointerType::new(unsafe { LLVMTypeOf(self.fn_value.value) };

    // in fact it's a function pointer type, so we find the actual function type as the element type of the pointer
    ptr_type.get_element_type().into_function_type()
}

Clearly, get_type breaks with opaque pointers: ptr_type.get_element_type() returns something invalid (just NULL maybe?) and the surrounding code will segfault.

But, LLVM should internally know the types of functions: we specify them on declaration. Is there some way to get that type back from an LLVMValueRef that points to the function using the C API?

The function type depends on the context use, it’s not associated with the pointer. You can call a function with the “wrong” type at different call sites using the same ptr value. You should look for the relevant use context hint for the type (e.g. call instructions have their own associated type)

consistent use of the context is handled elsewhere (and therefore assumed here). In this issue Support llvm-sys 150.x.x by hedgar2017 · Pull Request #383 · TheDan64/inkwell · GitHub we came up with

pub fn get_type(self) -> FunctionType<'ctx> {
    unsafe { FunctionType::new(llvm_sys::core::LLVMGlobalGetValueType(self.as_value_ref())) }
}

which seems to do the trick (since llvm 8.0, as far as I can see)

Yes, globals directly have the contained type. You don’t need to go through the pointer type