Skip to content

Commit 022b09e

Browse files
Introduced an UnsafeFunctionPointer trait
1 parent 8f51489 commit 022b09e

File tree

2 files changed

+35
-4
lines changed

2 files changed

+35
-4
lines changed

src/execution_engine.rs

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,9 @@ impl ExecutionEngine {
209209
/// The `Symbol` wrapper ensures a function won't accidentally outlive the
210210
/// execution engine it came from, but adding functions after calling this
211211
/// method *may* invalidate the function pointer.
212-
pub unsafe fn get_function<F>(&self, fn_name: &str) -> Result<Symbol<F>, FunctionLookupError> {
212+
pub unsafe fn get_function<F>(&self, fn_name: &str) -> Result<Symbol<F>, FunctionLookupError>
213+
where F: UnsafeFunctionPointer
214+
{
213215
if !self.jit_mode {
214216
return Err(FunctionLookupError::JITNotEnabled);
215217
}
@@ -294,19 +296,48 @@ impl ExecutionEngine {
294296
/// A wrapper around a function pointer which ensures the symbol being pointed
295297
/// to doesn't accidentally outlive its execution engine.
296298
#[derive(Debug, Clone)]
297-
pub struct Symbol<F> {
299+
pub struct Symbol<F: UnsafeFunctionPointer> {
298300
pub(crate) execution_engine: Rc<LLVMExecutionEngineRef>,
299301
inner: F,
300302
}
301303

302-
impl<F> Deref for Symbol<F> {
304+
impl<F: UnsafeFunctionPointer> Deref for Symbol<F> {
303305
type Target = F;
304306

305307
fn deref(&self) -> &Self::Target {
306308
&self.inner
307309
}
308310
}
309311

312+
/// Marker trait representing an unsafe function pointer (`unsafe extern "C" fn(A, B, ...) -> Output`).
313+
pub trait UnsafeFunctionPointer: private::Sealed {}
314+
315+
mod private {
316+
/// A sealed trait which ensures nobody outside this crate can implement
317+
/// `UnsafeFunctionPointer`.
318+
///
319+
/// See https://rust-lang-nursery.github.io/api-guidelines/future-proofing.html
320+
pub trait Sealed {}
321+
}
322+
323+
macro_rules! impl_unsafe_fn {
324+
($( $param:ident ),*) => {
325+
impl<Output, $( $param ),*> private::Sealed for unsafe extern "C" fn($( $param ),*) -> Output {}
326+
impl<Output, $( $param ),*> UnsafeFunctionPointer for unsafe extern "C" fn($( $param ),*) -> Output {}
327+
};
328+
}
329+
330+
impl_unsafe_fn!();
331+
impl_unsafe_fn!(A);
332+
impl_unsafe_fn!(A, B);
333+
impl_unsafe_fn!(A, B, C);
334+
impl_unsafe_fn!(A, B, C, D);
335+
impl_unsafe_fn!(A, B, C, D, E);
336+
impl_unsafe_fn!(A, B, C, D, E, F);
337+
impl_unsafe_fn!(A, B, C, D, E, F, G);
338+
impl_unsafe_fn!(A, B, C, D, E, F, G, H);
339+
impl_unsafe_fn!(A, B, C, D, E, F, G, H, I);
340+
310341
// Modules owned by the EE will be discarded by the EE so we don't
311342
// want owned modules to drop.
312343
impl Drop for ExecutionEngine {

tests/test_builder.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ fn test_binary_ops() {
206206
builder.build_return(Some(&xor));
207207

208208
unsafe {
209-
type BoolFunc = fn(bool, bool) -> bool;
209+
type BoolFunc = unsafe extern "C" fn(bool, bool) -> bool;
210210

211211
let and: Symbol<BoolFunc> = execution_engine.get_function("and").unwrap();
212212
let or: Symbol<BoolFunc> = execution_engine.get_function("or").unwrap();

0 commit comments

Comments
 (0)