| use std::ptr; | |
| use libc::c_uint; | |
| use rustc_abi::Align; | |
| use crate::llvm::debuginfo::DIBuilder; | |
| use crate::llvm::{self, Module, ToLlvmBool}; | |
| /// Owning pointer to a `DIBuilder<'ll>` that will dispose of the builder | |
| /// when dropped. Use `.as_ref()` to get the underlying `&DIBuilder` | |
| /// needed for debuginfo FFI calls. | |
| pub(crate) struct DIBuilderBox<'ll> { | |
| raw: ptr::NonNull<DIBuilder<'ll>>, | |
| } | |
| impl<'ll> DIBuilderBox<'ll> { | |
| pub(crate) fn new(llmod: &'ll Module) -> Self { | |
| let raw = unsafe { llvm::LLVMCreateDIBuilder(llmod) }; | |
| let raw = ptr::NonNull::new(raw).unwrap(); | |
| Self { raw } | |
| } | |
| pub(crate) fn as_ref(&self) -> &DIBuilder<'ll> { | |
| // SAFETY: This is an owning pointer, so `&DIBuilder` is valid | |
| // for as long as `&self` is. | |
| unsafe { self.raw.as_ref() } | |
| } | |
| } | |
| impl<'ll> Drop for DIBuilderBox<'ll> { | |
| fn drop(&mut self) { | |
| unsafe { llvm::LLVMDisposeDIBuilder(self.raw) }; | |
| } | |
| } | |
| /// Extension trait for defining safe wrappers and helper methods on | |
| /// `&DIBuilder<'ll>`, without requiring it to be defined in the same crate. | |
| pub(crate) trait DIBuilderExt<'ll> { | |
| fn as_di_builder(&self) -> &DIBuilder<'ll>; | |
| fn create_expression(&self, addr_ops: &[u64]) -> &'ll llvm::Metadata { | |
| let this = self.as_di_builder(); | |
| unsafe { llvm::LLVMDIBuilderCreateExpression(this, addr_ops.as_ptr(), addr_ops.len()) } | |
| } | |
| fn create_static_variable( | |
| &self, | |
| scope: Option<&'ll llvm::Metadata>, | |
| name: &str, | |
| linkage_name: &str, | |
| file: &'ll llvm::Metadata, | |
| line_number: c_uint, | |
| ty: &'ll llvm::Metadata, | |
| is_local_to_unit: bool, | |
| val: &'ll llvm::Value, | |
| decl: Option<&'ll llvm::Metadata>, | |
| align: Option<Align>, | |
| ) -> &'ll llvm::Metadata { | |
| let this = self.as_di_builder(); | |
| let align_in_bits = align.map_or(0, |align| align.bits() as u32); | |
| // `LLVMDIBuilderCreateGlobalVariableExpression` would assert if we | |
| // gave it a null `Expr` pointer, so give it an empty expression | |
| // instead, which is what the C++ `createGlobalVariableExpression` | |
| // method would do if given a null `DIExpression` pointer. | |
| let expr = self.create_expression(&[]); | |
| let global_var_expr = unsafe { | |
| llvm::LLVMDIBuilderCreateGlobalVariableExpression( | |
| this, | |
| scope, | |
| name.as_ptr(), | |
| name.len(), | |
| linkage_name.as_ptr(), | |
| linkage_name.len(), | |
| file, | |
| line_number, | |
| ty, | |
| is_local_to_unit.to_llvm_bool(), | |
| expr, | |
| decl, | |
| align_in_bits, | |
| ) | |
| }; | |
| unsafe { llvm::LLVMGlobalSetMetadata(val, llvm::MD_dbg, global_var_expr) }; | |
| global_var_expr | |
| } | |
| } | |
| impl<'ll> DIBuilderExt<'ll> for &DIBuilder<'ll> { | |
| fn as_di_builder(&self) -> &DIBuilder<'ll> { | |
| self | |
| } | |
| // All other methods have default bodies that rely on `as_di_builder`. | |
| } |