rustc_codegen_llvm/back/
owned_target_machine.rs

1use std::assert_matches::assert_matches;
2use std::ffi::CStr;
3use std::marker::PhantomData;
4use std::ptr::NonNull;
5
6use rustc_data_structures::small_c_str::SmallCStr;
7
8use crate::errors::LlvmError;
9use crate::llvm;
10
11/// Responsible for safely creating and disposing llvm::TargetMachine via ffi functions.
12/// Not cloneable as there is no clone function for llvm::TargetMachine.
13#[repr(transparent)]
14pub struct OwnedTargetMachine {
15    tm_unique: NonNull<llvm::TargetMachine>,
16    phantom: PhantomData<llvm::TargetMachine>,
17}
18
19impl OwnedTargetMachine {
20    pub(crate) fn new(
21        triple: &CStr,
22        cpu: &CStr,
23        features: &CStr,
24        abi: &CStr,
25        model: llvm::CodeModel,
26        reloc: llvm::RelocModel,
27        level: llvm::CodeGenOptLevel,
28        float_abi: llvm::FloatAbi,
29        function_sections: bool,
30        data_sections: bool,
31        unique_section_names: bool,
32        trap_unreachable: bool,
33        singlethread: bool,
34        verbose_asm: bool,
35        emit_stack_size_section: bool,
36        relax_elf_relocations: bool,
37        use_init_array: bool,
38        split_dwarf_file: &CStr,
39        output_obj_file: &CStr,
40        debug_info_compression: &CStr,
41        use_emulated_tls: bool,
42        args_cstr_buff: &[u8],
43        use_wasm_eh: bool,
44    ) -> Result<Self, LlvmError<'static>> {
45        // The argument list is passed as the concatenation of one or more C strings.
46        // This implies that there must be a last byte, and it must be 0.
47        assert_matches!(args_cstr_buff, [.., b'\0'], "the last byte must be a NUL terminator");
48
49        // SAFETY: llvm::LLVMRustCreateTargetMachine copies pointed to data
50        let tm_ptr = unsafe {
51            llvm::LLVMRustCreateTargetMachine(
52                triple.as_ptr(),
53                cpu.as_ptr(),
54                features.as_ptr(),
55                abi.as_ptr(),
56                model,
57                reloc,
58                level,
59                float_abi,
60                function_sections,
61                data_sections,
62                unique_section_names,
63                trap_unreachable,
64                singlethread,
65                verbose_asm,
66                emit_stack_size_section,
67                relax_elf_relocations,
68                use_init_array,
69                split_dwarf_file.as_ptr(),
70                output_obj_file.as_ptr(),
71                debug_info_compression.as_ptr(),
72                use_emulated_tls,
73                args_cstr_buff.as_ptr(),
74                args_cstr_buff.len(),
75                use_wasm_eh,
76            )
77        };
78
79        NonNull::new(tm_ptr)
80            .map(|tm_unique| Self { tm_unique, phantom: PhantomData })
81            .ok_or_else(|| LlvmError::CreateTargetMachine { triple: SmallCStr::from(triple) })
82    }
83
84    /// Returns inner `llvm::TargetMachine` type.
85    ///
86    /// This could be a `Deref` implementation, but `llvm::TargetMachine` is an extern type and
87    /// `Deref::Target: ?Sized`.
88    pub fn raw(&self) -> &llvm::TargetMachine {
89        // SAFETY: constructing ensures we have a valid pointer created by
90        // llvm::LLVMRustCreateTargetMachine.
91        unsafe { self.tm_unique.as_ref() }
92    }
93}
94
95impl Drop for OwnedTargetMachine {
96    fn drop(&mut self) {
97        // SAFETY: constructing ensures we have a valid pointer created by
98        // llvm::LLVMRustCreateTargetMachine OwnedTargetMachine is not copyable so there is no
99        // double free or use after free.
100        unsafe {
101            llvm::LLVMRustDisposeTargetMachine(self.tm_unique.as_ptr());
102        }
103    }
104}