diff options
| author | Zalathar <Zalathar@users.noreply.github.com> | 2024-11-03 12:40:26 +1100 |
|---|---|---|
| committer | Zalathar <Zalathar@users.noreply.github.com> | 2024-11-09 11:07:44 +1100 |
| commit | 89d7efaf8f5ed8c1c15faea21824ae479656bdc1 (patch) | |
| tree | d296072221ae1181417acce0273050121a69d9f2 /compiler/rustc_llvm/src | |
| parent | 730626dbd924d7fbf3873bcf1da783f486efd1d7 (diff) | |
| download | rust-89d7efaf8f5ed8c1c15faea21824ae479656bdc1.tar.gz rust-89d7efaf8f5ed8c1c15faea21824ae479656bdc1.zip | |
Make `RustString` an extern type to avoid `improper_ctypes` warnings
Diffstat (limited to 'compiler/rustc_llvm/src')
| -rw-r--r-- | compiler/rustc_llvm/src/lib.rs | 69 |
1 files changed, 51 insertions, 18 deletions
diff --git a/compiler/rustc_llvm/src/lib.rs b/compiler/rustc_llvm/src/lib.rs index 055d2bd5bc9..eda9b2b1fc0 100644 --- a/compiler/rustc_llvm/src/lib.rs +++ b/compiler/rustc_llvm/src/lib.rs @@ -2,42 +2,75 @@ #![allow(internal_features)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] +#![feature(extern_types)] #![feature(rustdoc_internals)] #![warn(unreachable_pub)] // tidy-alphabetical-end -// NOTE: This crate only exists to allow linking on mingw targets. - use std::cell::RefCell; -use std::slice; +use std::{ptr, slice}; -use libc::{c_char, size_t}; +use libc::size_t; -#[repr(C)] -pub struct RustString { - pub bytes: RefCell<Vec<u8>>, +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 len(&self) -> usize { - self.bytes.borrow().len() + pub fn build_byte_buffer(closure: impl FnOnce(&Self)) -> Vec<u8> { + let buf = RustStringInner::default(); + closure(buf.as_opaque()); + buf.into_inner() } +} - pub fn is_empty(&self) -> bool { - self.bytes.borrow().is_empty() +/// 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() } } -/// Appending to a Rust string -- used by RawRustStringOstream. +/// 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( - sr: &RustString, - ptr: *const c_char, - size: size_t, + buf: &RustString, + slice_ptr: *const u8, // Same ABI as `*const c_char` + slice_len: size_t, ) { - let slice = unsafe { slice::from_raw_parts(ptr as *const u8, size) }; - - sr.bytes.borrow_mut().extend_from_slice(slice); + 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 = "...")`. |
