| // tidy-alphabetical-start | |
| #![feature(extern_types)] | |
| // tidy-alphabetical-end | |
| use std::cell::RefCell; | |
| use std::{ptr, slice}; | |
| use libc::size_t; | |
| unsafe extern "C" { | |
| /// Opaque type that allows C++ code to write bytes to a Rust-side buffer, | |
| /// in conjunction with `RawRustStringOstream`. Use this as `&RustString` | |
| /// (Rust) and `RustStringRef` (C++) in FFI signatures. | |
| pub type RustString; | |
| } | |
| impl RustString { | |
| pub fn build_byte_buffer(closure: impl FnOnce(&Self)) -> Vec<u8> { | |
| let buf = RustStringInner::default(); | |
| closure(buf.as_opaque()); | |
| buf.into_inner() | |
| } | |
| } | |
| /// Underlying implementation of [`RustString`]. | |
| /// | |
| /// Having two separate types makes it possible to use the opaque [`RustString`] | |
| /// in FFI signatures without `improper_ctypes` warnings. This is a workaround | |
| /// for the fact that there is no way to opt out of `improper_ctypes` when | |
| /// _declaring_ a type (as opposed to using that type). | |
| #[derive(Default)] | |
| struct RustStringInner { | |
| bytes: RefCell<Vec<u8>>, | |
| } | |
| impl RustStringInner { | |
| fn as_opaque(&self) -> &RustString { | |
| let ptr: *const RustStringInner = ptr::from_ref(self); | |
| // We can't use `ptr::cast` here because extern types are `!Sized`. | |
| let ptr = ptr as *const RustString; | |
| unsafe { &*ptr } | |
| } | |
| fn from_opaque(opaque: &RustString) -> &Self { | |
| // SAFETY: A valid `&RustString` must have been created via `as_opaque`. | |
| let ptr: *const RustString = ptr::from_ref(opaque); | |
| let ptr: *const RustStringInner = ptr.cast(); | |
| unsafe { &*ptr } | |
| } | |
| fn into_inner(self) -> Vec<u8> { | |
| self.bytes.into_inner() | |
| } | |
| } | |
| /// Appends the contents of a byte slice to a [`RustString`]. | |
| /// | |
| /// This function is implemented in `rustc_llvm` so that the C++ code in this | |
| /// crate can link to it directly, without an implied link-time dependency on | |
| /// `rustc_codegen_llvm`. | |
| #[unsafe(no_mangle)] | |
| pub unsafe extern "C" fn LLVMRustStringWriteImpl( | |
| buf: &RustString, | |
| slice_ptr: *const u8, // Same ABI as `*const c_char` | |
| slice_len: size_t, | |
| ) { | |
| let slice = unsafe { slice::from_raw_parts(slice_ptr, slice_len) }; | |
| RustStringInner::from_opaque(buf).bytes.borrow_mut().extend_from_slice(slice); | |
| } | |
| /// Initialize targets enabled by the build script via `cfg(llvm_component = "...")`. | |
| /// N.B., this function can't be moved to `rustc_codegen_llvm` because of the `cfg`s. | |
| pub fn initialize_available_targets() { | |
| macro_rules! init_target( | |
| ($cfg:meta, $($method:ident),*) => { { | |
| #[cfg($cfg)] | |
| fn init() { | |
| unsafe extern "C" { | |
| $(fn $method();)* | |
| } | |
| unsafe { | |
| $($method();)* | |
| } | |
| } | |
| #[cfg(not($cfg))] | |
| fn init() { } | |
| init(); | |
| } } | |
| ); | |
| init_target!( | |
| llvm_component = "x86", | |
| LLVMInitializeX86TargetInfo, | |
| LLVMInitializeX86Target, | |
| LLVMInitializeX86TargetMC, | |
| LLVMInitializeX86AsmPrinter, | |
| LLVMInitializeX86AsmParser | |
| ); | |
| init_target!( | |
| llvm_component = "arm", | |
| LLVMInitializeARMTargetInfo, | |
| LLVMInitializeARMTarget, | |
| LLVMInitializeARMTargetMC, | |
| LLVMInitializeARMAsmPrinter, | |
| LLVMInitializeARMAsmParser | |
| ); | |
| init_target!( | |
| llvm_component = "aarch64", | |
| LLVMInitializeAArch64TargetInfo, | |
| LLVMInitializeAArch64Target, | |
| LLVMInitializeAArch64TargetMC, | |
| LLVMInitializeAArch64AsmPrinter, | |
| LLVMInitializeAArch64AsmParser | |
| ); | |
| init_target!( | |
| llvm_component = "amdgpu", | |
| LLVMInitializeAMDGPUTargetInfo, | |
| LLVMInitializeAMDGPUTarget, | |
| LLVMInitializeAMDGPUTargetMC, | |
| LLVMInitializeAMDGPUAsmPrinter, | |
| LLVMInitializeAMDGPUAsmParser | |
| ); | |
| init_target!( | |
| llvm_component = "avr", | |
| LLVMInitializeAVRTargetInfo, | |
| LLVMInitializeAVRTarget, | |
| LLVMInitializeAVRTargetMC, | |
| LLVMInitializeAVRAsmPrinter, | |
| LLVMInitializeAVRAsmParser | |
| ); | |
| init_target!( | |
| llvm_component = "m68k", | |
| LLVMInitializeM68kTargetInfo, | |
| LLVMInitializeM68kTarget, | |
| LLVMInitializeM68kTargetMC, | |
| LLVMInitializeM68kAsmPrinter, | |
| LLVMInitializeM68kAsmParser | |
| ); | |
| init_target!( | |
| llvm_component = "csky", | |
| LLVMInitializeCSKYTargetInfo, | |
| LLVMInitializeCSKYTarget, | |
| LLVMInitializeCSKYTargetMC, | |
| LLVMInitializeCSKYAsmPrinter, | |
| LLVMInitializeCSKYAsmParser | |
| ); | |
| init_target!( | |
| llvm_component = "loongarch", | |
| LLVMInitializeLoongArchTargetInfo, | |
| LLVMInitializeLoongArchTarget, | |
| LLVMInitializeLoongArchTargetMC, | |
| LLVMInitializeLoongArchAsmPrinter, | |
| LLVMInitializeLoongArchAsmParser | |
| ); | |
| init_target!( | |
| llvm_component = "mips", | |
| LLVMInitializeMipsTargetInfo, | |
| LLVMInitializeMipsTarget, | |
| LLVMInitializeMipsTargetMC, | |
| LLVMInitializeMipsAsmPrinter, | |
| LLVMInitializeMipsAsmParser | |
| ); | |
| init_target!( | |
| llvm_component = "powerpc", | |
| LLVMInitializePowerPCTargetInfo, | |
| LLVMInitializePowerPCTarget, | |
| LLVMInitializePowerPCTargetMC, | |
| LLVMInitializePowerPCAsmPrinter, | |
| LLVMInitializePowerPCAsmParser | |
| ); | |
| init_target!( | |
| llvm_component = "systemz", | |
| LLVMInitializeSystemZTargetInfo, | |
| LLVMInitializeSystemZTarget, | |
| LLVMInitializeSystemZTargetMC, | |
| LLVMInitializeSystemZAsmPrinter, | |
| LLVMInitializeSystemZAsmParser | |
| ); | |
| init_target!( | |
| llvm_component = "msp430", | |
| LLVMInitializeMSP430TargetInfo, | |
| LLVMInitializeMSP430Target, | |
| LLVMInitializeMSP430TargetMC, | |
| LLVMInitializeMSP430AsmPrinter, | |
| LLVMInitializeMSP430AsmParser | |
| ); | |
| init_target!( | |
| llvm_component = "riscv", | |
| LLVMInitializeRISCVTargetInfo, | |
| LLVMInitializeRISCVTarget, | |
| LLVMInitializeRISCVTargetMC, | |
| LLVMInitializeRISCVAsmPrinter, | |
| LLVMInitializeRISCVAsmParser | |
| ); | |
| init_target!( | |
| llvm_component = "sparc", | |
| LLVMInitializeSparcTargetInfo, | |
| LLVMInitializeSparcTarget, | |
| LLVMInitializeSparcTargetMC, | |
| LLVMInitializeSparcAsmPrinter, | |
| LLVMInitializeSparcAsmParser | |
| ); | |
| init_target!( | |
| llvm_component = "nvptx", | |
| LLVMInitializeNVPTXTargetInfo, | |
| LLVMInitializeNVPTXTarget, | |
| LLVMInitializeNVPTXTargetMC, | |
| LLVMInitializeNVPTXAsmPrinter | |
| ); | |
| init_target!( | |
| llvm_component = "hexagon", | |
| LLVMInitializeHexagonTargetInfo, | |
| LLVMInitializeHexagonTarget, | |
| LLVMInitializeHexagonTargetMC, | |
| LLVMInitializeHexagonAsmPrinter, | |
| LLVMInitializeHexagonAsmParser | |
| ); | |
| init_target!( | |
| llvm_component = "xtensa", | |
| LLVMInitializeXtensaTargetInfo, | |
| LLVMInitializeXtensaTarget, | |
| LLVMInitializeXtensaTargetMC, | |
| LLVMInitializeXtensaAsmPrinter, | |
| LLVMInitializeXtensaAsmParser | |
| ); | |
| init_target!( | |
| llvm_component = "webassembly", | |
| LLVMInitializeWebAssemblyTargetInfo, | |
| LLVMInitializeWebAssemblyTarget, | |
| LLVMInitializeWebAssemblyTargetMC, | |
| LLVMInitializeWebAssemblyAsmPrinter, | |
| LLVMInitializeWebAssemblyAsmParser | |
| ); | |
| init_target!( | |
| llvm_component = "bpf", | |
| LLVMInitializeBPFTargetInfo, | |
| LLVMInitializeBPFTarget, | |
| LLVMInitializeBPFTargetMC, | |
| LLVMInitializeBPFAsmPrinter, | |
| LLVMInitializeBPFAsmParser | |
| ); | |
| } |