I am trying to learn the Inkwell LLVM wrapper in Rust. I have been getting a GEPPointee error when trying to run the following program. The program attempts to create a struct allocation, and initialize the struct fields. I am having trouble understanding how to access the fields. I believe that my understanding of how the ‘build_struct_gep’ function works is incorrect.
As far as I understand the GEPPointee error comes from trying to access a non-struct pointer as if it were a struct pointer with the ‘build_struct_gep’ function. Why am I getting this error? I thought that when I create the allocation I receive a struct pointer. How can I correctly create a struct allocation and access a structs field.
Thank you all.
use inkwell::context::Context;
use inkwell::module::{Linkage};
use inkwell::types::{BasicType, BasicTypeEnum};
use inkwell::values::BasicValueEnum;
use inkwell::AddressSpace;
fn main() {
let ctx = Context::create();
let module = ctx.create_module("main");
// create printf fn
let printf_ty = ctx.void_type().fn_type(&[ctx.i8_type().ptr_type(AddressSpace::default()).into()], true);
let printf_val = module.add_function("printf", printf_ty, Some(Linkage::External));
// create main fn
let main_fn_val = module.add_function("main", ctx.i32_type().fn_type(&[], false), None);
let main_entry = ctx.append_basic_block(main_fn_val, "entry");
let main_begin = ctx.append_basic_block(main_fn_val, "begin");
// create entry builder
let eb = ctx.create_builder();
eb.position_at_end(main_entry);
let init_branch = eb.build_unconditional_branch(main_begin).unwrap();
eb.position_before(&init_branch);
// create main builder
let mb = ctx.create_builder();
mb.position_at_end(main_begin);
// create car struct type
let field_types = [
ctx
.i8_type()
.ptr_type(AddressSpace::default())
.as_basic_type_enum(),
ctx
.i8_type()
.ptr_type(AddressSpace::default())
.as_basic_type_enum(),
ctx.i32_type().as_basic_type_enum(),
];
let car_struct_type = ctx.struct_type(&field_types, false);
// create car struct allocation
let car_struct_ptr = eb.build_alloca(car_struct_type, "car_struct").unwrap();
// create car struct field values
macro_rules! glob_str {
($string:literal) => {
{
let string = unsafe { eb.build_global_string($string, "static_string") }.unwrap();
string.set_constant(false);
string.as_pointer_value()
}
};
}
let str_type = ctx.i8_type().into();
let brand_name = glob_str!("ford").into();
let model_name = glob_str!("mustang").into();
let int_type = ctx.i32_type().into();
let year = ctx.i32_type().const_int(2024, false).into();
// store values in struct allocation
let values: &[(BasicValueEnum, BasicTypeEnum)] = &[
(brand_name, str_type),
(model_name, str_type),
(year, int_type),
];
for (idx, (value, ty)) in values.iter().enumerate() {
let ptr = eb.build_struct_gep(*ty, car_struct_ptr, idx as u32, &format!("get_struct_member__{idx}")).unwrap();
eb.build_store(ptr, *value).unwrap();
}
}
I do not know what to try, and the documentation that is specific to Inkwell is sparse.
Jake Snell is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.