Skip to content

Commit 730d088

Browse files
committed
Make RustString an extern type to avoid improper_ctypes warnings
1 parent 8b76c44 commit 730d088

File tree

4 files changed

+62
-45
lines changed

4 files changed

+62
-45
lines changed

compiler/rustc_codegen_llvm/src/llvm/ffi.rs

-18
Original file line numberDiff line numberDiff line change
@@ -1789,7 +1789,6 @@ unsafe extern "C" {
17891789
ConstraintsLen: size_t,
17901790
) -> bool;
17911791

1792-
#[allow(improper_ctypes)]
17931792
pub(crate) fn LLVMRustCoverageWriteFilenamesSectionToBuffer(
17941793
Filenames: *const *const c_char,
17951794
FilenamesLen: size_t,
@@ -1798,7 +1797,6 @@ unsafe extern "C" {
17981797
BufferOut: &RustString,
17991798
);
18001799

1801-
#[allow(improper_ctypes)]
18021800
pub(crate) fn LLVMRustCoverageWriteMappingToBuffer(
18031801
VirtualFileMappingIDs: *const c_uint,
18041802
NumVirtualFileMappingIDs: c_uint,
@@ -1821,14 +1819,8 @@ unsafe extern "C" {
18211819
FuncNameLen: size_t,
18221820
) -> &Value;
18231821
pub(crate) fn LLVMRustCoverageHashByteArray(Bytes: *const c_char, NumBytes: size_t) -> u64;
1824-
1825-
#[allow(improper_ctypes)]
18261822
pub(crate) fn LLVMRustCoverageWriteMapSectionNameToString(M: &Module, Str: &RustString);
1827-
1828-
#[allow(improper_ctypes)]
18291823
pub(crate) fn LLVMRustCoverageWriteFuncSectionNameToString(M: &Module, Str: &RustString);
1830-
1831-
#[allow(improper_ctypes)]
18321824
pub(crate) fn LLVMRustCoverageWriteMappingVarNameToString(Str: &RustString);
18331825

18341826
pub(crate) fn LLVMRustCoverageMappingVersion() -> u32;
@@ -2183,14 +2175,11 @@ unsafe extern "C" {
21832175
pub fn LLVMRustDIBuilderCreateOpPlusUconst() -> u64;
21842176
pub fn LLVMRustDIBuilderCreateOpLLVMFragment() -> u64;
21852177

2186-
#[allow(improper_ctypes)]
21872178
pub fn LLVMRustWriteTypeToString(Type: &Type, s: &RustString);
2188-
#[allow(improper_ctypes)]
21892179
pub fn LLVMRustWriteValueToString(value_ref: &Value, s: &RustString);
21902180

21912181
pub fn LLVMRustHasFeature(T: &TargetMachine, s: *const c_char) -> bool;
21922182

2193-
#[allow(improper_ctypes)]
21942183
pub(crate) fn LLVMRustPrintTargetCPUs(TM: &TargetMachine, OutStr: &RustString);
21952184
pub fn LLVMRustGetTargetFeaturesCount(T: &TargetMachine) -> size_t;
21962185
pub fn LLVMRustGetTargetFeature(
@@ -2295,10 +2284,8 @@ unsafe extern "C" {
22952284
pub fn LLVMRustArchiveIteratorFree<'a>(AIR: &'a mut ArchiveIterator<'a>);
22962285
pub fn LLVMRustDestroyArchive(AR: &'static mut Archive);
22972286

2298-
#[allow(improper_ctypes)]
22992287
pub fn LLVMRustWriteTwineToString(T: &Twine, s: &RustString);
23002288

2301-
#[allow(improper_ctypes)]
23022289
pub fn LLVMRustUnpackOptimizationDiagnostic<'a>(
23032290
DI: &'a DiagnosticInfo,
23042291
pass_name_out: &RustString,
@@ -2316,7 +2303,6 @@ unsafe extern "C" {
23162303
message_out: &mut Option<&'a Twine>,
23172304
);
23182305

2319-
#[allow(improper_ctypes)]
23202306
pub fn LLVMRustWriteDiagnosticInfoToString(DI: &DiagnosticInfo, s: &RustString);
23212307
pub fn LLVMRustGetDiagInfoKind(DI: &DiagnosticInfo) -> DiagnosticKind;
23222308

@@ -2325,7 +2311,6 @@ unsafe extern "C" {
23252311
cookie_out: &mut c_uint,
23262312
) -> &'a SMDiagnostic;
23272313

2328-
#[allow(improper_ctypes)]
23292314
pub fn LLVMRustUnpackSMDiagnostic(
23302315
d: &SMDiagnostic,
23312316
message_out: &RustString,
@@ -2372,7 +2357,6 @@ unsafe extern "C" {
23722357
pub fn LLVMRustModuleBufferLen(p: &ModuleBuffer) -> usize;
23732358
pub fn LLVMRustModuleBufferFree(p: &'static mut ModuleBuffer);
23742359
pub fn LLVMRustModuleCost(M: &Module) -> u64;
2375-
#[allow(improper_ctypes)]
23762360
pub fn LLVMRustModuleInstructionStats(M: &Module, Str: &RustString);
23772361

23782362
pub fn LLVMRustThinLTOBufferCreate(
@@ -2425,7 +2409,6 @@ unsafe extern "C" {
24252409
bytecode_len: usize,
24262410
) -> bool;
24272411
pub fn LLVMRustLinkerFree<'a>(linker: &'a mut Linker<'a>);
2428-
#[allow(improper_ctypes)]
24292412
pub fn LLVMRustComputeLTOCacheKey(
24302413
key_out: &RustString,
24312414
mod_id: *const c_char,
@@ -2448,7 +2431,6 @@ unsafe extern "C" {
24482431
pgo_available: bool,
24492432
);
24502433

2451-
#[allow(improper_ctypes)]
24522434
pub fn LLVMRustGetMangledName(V: &Value, out: &RustString);
24532435

24542436
pub fn LLVMRustGetElementTypeArgIndex(CallSite: &Value) -> i32;

compiler/rustc_codegen_llvm/src/llvm/mod.rs

+2-7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#![allow(non_snake_case)]
22

3-
use std::cell::RefCell;
43
use std::ffi::{CStr, CString};
54
use std::ops::Deref;
65
use std::ptr;
@@ -301,15 +300,11 @@ pub fn set_value_name(value: &Value, name: &[u8]) {
301300
}
302301

303302
pub fn build_string(f: impl FnOnce(&RustString)) -> Result<String, FromUtf8Error> {
304-
let sr = RustString { bytes: RefCell::new(Vec::new()) };
305-
f(&sr);
306-
String::from_utf8(sr.bytes.into_inner())
303+
String::from_utf8(RustString::build_byte_buffer(f))
307304
}
308305

309306
pub fn build_byte_buffer(f: impl FnOnce(&RustString)) -> Vec<u8> {
310-
let sr = RustString { bytes: RefCell::new(Vec::new()) };
311-
f(&sr);
312-
sr.bytes.into_inner()
307+
RustString::build_byte_buffer(f)
313308
}
314309

315310
pub fn twine_to_string(tr: &Twine) -> String {

compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,9 @@ typedef struct OpaqueRustString *RustStringRef;
104104
typedef struct LLVMOpaqueTwine *LLVMTwineRef;
105105
typedef struct LLVMOpaqueSMDiagnostic *LLVMSMDiagnosticRef;
106106

107-
extern "C" void LLVMRustStringWriteImpl(RustStringRef Str, const char *Ptr,
108-
size_t Size);
107+
extern "C" void LLVMRustStringWriteImpl(RustStringRef buf,
108+
const char *slice_ptr,
109+
size_t slice_len);
109110

110111
class RawRustStringOstream : public llvm::raw_ostream {
111112
RustStringRef Str;

compiler/rustc_llvm/src/lib.rs

+57-18
Original file line numberDiff line numberDiff line change
@@ -2,42 +2,81 @@
22
#![allow(internal_features)]
33
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
44
#![doc(rust_logo)]
5+
#![feature(extern_types)]
56
#![feature(rustdoc_internals)]
67
#![warn(unreachable_pub)]
78
// tidy-alphabetical-end
89

9-
// NOTE: This crate only exists to allow linking on mingw targets.
10-
1110
use std::cell::RefCell;
12-
use std::slice;
11+
use std::ops::Deref;
12+
use std::{ptr, slice};
1313

14-
use libc::{c_char, size_t};
14+
use libc::size_t;
1515

16-
#[repr(C)]
17-
pub struct RustString {
18-
pub bytes: RefCell<Vec<u8>>,
16+
unsafe extern "C" {
17+
/// Opaque type that allows C++ code to write bytes to a Rust-side buffer,
18+
/// in conjunction with `RawRustStringOstream`. Use this as `&RustString`
19+
/// (Rust) and `RustStringRef` (C++) in FFI signatures.
20+
pub type RustString;
1921
}
2022

2123
impl RustString {
22-
pub fn len(&self) -> usize {
23-
self.bytes.borrow().len()
24+
pub fn build_byte_buffer(closure: impl FnOnce(&Self)) -> Vec<u8> {
25+
let buf = RustStringInner::default();
26+
closure(&buf);
27+
buf.into_inner()
28+
}
29+
}
30+
31+
/// Underlying implementation of [`RustString`].
32+
///
33+
/// Having two separate types makes it possible to use the opaque [`RustString`]
34+
/// in FFI signatures without `improper_ctypes` warnings. This is a workaround
35+
/// for the fact that there is no way to opt out of `improper_ctypes` when
36+
/// _declaring_ a type (as opposed to using that type).
37+
#[derive(Default)]
38+
struct RustStringInner {
39+
bytes: RefCell<Vec<u8>>,
40+
}
41+
42+
impl RustStringInner {
43+
fn from_opaque(opaque: &RustString) -> &Self {
44+
// SAFETY: A valid `&RustString` must have been created via deref of
45+
// `RustStringInner`.
46+
let ptr: *const RustString = ptr::from_ref(opaque);
47+
let ptr: *const RustStringInner = ptr.cast();
48+
unsafe { ptr.as_ref() }.unwrap()
2449
}
2550

26-
pub fn is_empty(&self) -> bool {
27-
self.bytes.borrow().is_empty()
51+
fn into_inner(self) -> Vec<u8> {
52+
self.bytes.into_inner()
2853
}
2954
}
3055

31-
/// Appending to a Rust string -- used by RawRustStringOstream.
56+
impl Deref for RustStringInner {
57+
type Target = RustString;
58+
59+
fn deref(&self) -> &Self::Target {
60+
let ptr: *const RustStringInner = ptr::from_ref(self);
61+
// We can't use `ptr::cast` here because extern types are `!Sized`.
62+
let ptr = ptr as *const RustString;
63+
unsafe { ptr.as_ref() }.unwrap()
64+
}
65+
}
66+
67+
/// Appends the contents of a byte slice to a [`RustString`].
68+
///
69+
/// This function is implemented in `rustc_llvm` so that the C++ code in this
70+
/// crate can link to it directly, without an implied link-time dependency on
71+
/// `rustc_codegen_llvm`.
3272
#[unsafe(no_mangle)]
3373
pub unsafe extern "C" fn LLVMRustStringWriteImpl(
34-
sr: &RustString,
35-
ptr: *const c_char,
36-
size: size_t,
74+
buf: &RustString,
75+
slice_ptr: *const u8, // Same ABI as `*const c_char`
76+
slice_len: size_t,
3777
) {
38-
let slice = unsafe { slice::from_raw_parts(ptr as *const u8, size) };
39-
40-
sr.bytes.borrow_mut().extend_from_slice(slice);
78+
let slice = unsafe { slice::from_raw_parts(slice_ptr, slice_len) };
79+
RustStringInner::from_opaque(buf).bytes.borrow_mut().extend_from_slice(slice);
4180
}
4281

4382
/// Initialize targets enabled by the build script via `cfg(llvm_component = "...")`.

0 commit comments

Comments
 (0)