rustc_codegen_llvm/debuginfo/
di_builder.rs

1use std::ptr;
2
3use libc::c_uint;
4use rustc_abi::Align;
5
6use crate::llvm::debuginfo::DIBuilder;
7use crate::llvm::{self, Module, ToLlvmBool};
8
9/// Owning pointer to a `DIBuilder<'ll>` that will dispose of the builder
10/// when dropped. Use `.as_ref()` to get the underlying `&DIBuilder`
11/// needed for debuginfo FFI calls.
12pub(crate) struct DIBuilderBox<'ll> {
13    raw: ptr::NonNull<DIBuilder<'ll>>,
14}
15
16impl<'ll> DIBuilderBox<'ll> {
17    pub(crate) fn new(llmod: &'ll Module) -> Self {
18        let raw = unsafe { llvm::LLVMCreateDIBuilder(llmod) };
19        let raw = ptr::NonNull::new(raw).unwrap();
20        Self { raw }
21    }
22
23    pub(crate) fn as_ref(&self) -> &DIBuilder<'ll> {
24        // SAFETY: This is an owning pointer, so `&DIBuilder` is valid
25        // for as long as `&self` is.
26        unsafe { self.raw.as_ref() }
27    }
28}
29
30impl<'ll> Drop for DIBuilderBox<'ll> {
31    fn drop(&mut self) {
32        unsafe { llvm::LLVMDisposeDIBuilder(self.raw) };
33    }
34}
35
36/// Extension trait for defining safe wrappers and helper methods on
37/// `&DIBuilder<'ll>`, without requiring it to be defined in the same crate.
38pub(crate) trait DIBuilderExt<'ll> {
39    fn as_di_builder(&self) -> &DIBuilder<'ll>;
40
41    fn create_expression(&self, addr_ops: &[u64]) -> &'ll llvm::Metadata {
42        let this = self.as_di_builder();
43        unsafe { llvm::LLVMDIBuilderCreateExpression(this, addr_ops.as_ptr(), addr_ops.len()) }
44    }
45
46    fn create_static_variable(
47        &self,
48        scope: Option<&'ll llvm::Metadata>,
49        name: &str,
50        linkage_name: &str,
51        file: &'ll llvm::Metadata,
52        line_number: c_uint,
53        ty: &'ll llvm::Metadata,
54        is_local_to_unit: bool,
55        val: &'ll llvm::Value,
56        decl: Option<&'ll llvm::Metadata>,
57        align: Option<Align>,
58    ) -> &'ll llvm::Metadata {
59        let this = self.as_di_builder();
60        let align_in_bits = align.map_or(0, |align| align.bits() as u32);
61
62        // `LLVMDIBuilderCreateGlobalVariableExpression` would assert if we
63        // gave it a null `Expr` pointer, so give it an empty expression
64        // instead, which is what the C++ `createGlobalVariableExpression`
65        // method would do if given a null `DIExpression` pointer.
66        let expr = self.create_expression(&[]);
67
68        let global_var_expr = unsafe {
69            llvm::LLVMDIBuilderCreateGlobalVariableExpression(
70                this,
71                scope,
72                name.as_ptr(),
73                name.len(),
74                linkage_name.as_ptr(),
75                linkage_name.len(),
76                file,
77                line_number,
78                ty,
79                is_local_to_unit.to_llvm_bool(),
80                expr,
81                decl,
82                align_in_bits,
83            )
84        };
85
86        unsafe { llvm::LLVMGlobalSetMetadata(val, llvm::MD_dbg, global_var_expr) };
87
88        global_var_expr
89    }
90}
91
92impl<'ll> DIBuilderExt<'ll> for &DIBuilder<'ll> {
93    fn as_di_builder(&self) -> &DIBuilder<'ll> {
94        self
95    }
96
97    // All other methods have default bodies that rely on `as_di_builder`.
98}