rust-lang / rust-lang/rfcs

Allow "ABI agnostic" generics in FFI imports.

Open
#2,770 5 comments 13 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-ffi T-lang
Dominant language
Markdown
Stars
6.6k
Forks
1.7k
Avg merge
16h 14m
Merged PRs (30d)
1

Description

For example, a C library might have the following API:

// All examples below assume these two types.
extern "C" {
    type Foo;
    type Bar;
}
extern "C" {
    fn foo_each_bar(
        foo: *mut Foo,
        callback_data: *mut c_void,
        callback: unsafe extern "C" fn(*mut c_void, *mut Bar),
    );
}

However, the c_void pointee makes it harder to use (having to cast to and from *mut c_void) and more error-prone (having no real type safety other than "it's a raw pointer and unsafe to deref").

We could, instead, allow this definition:

extern "C" {
    fn foo_each_bar<T>(
        foo: *mut Foo,
        callback_data: *mut T,
        callback: unsafe extern "C" fn(*mut T, *mut Bar),
    );
}

This is valid because we can fully compute the call ABI for foo_each_bar::<T> without knowing T (and this is something rustc has been able to do independently of LLVM for a while now).
If, e.g. <T> is replaced with <T: ?Sized>, the definition would be disallowed, since the layout of *mut T would then depend on the choice of T, as opposed to always being a pointer scalar.

If that last example works, we can also combine it with Rust references:

extern "C" {
    fn foo_each_bar<T>(
        foo: &Foo,
        callback_data: &mut T,
        callback: extern "C" fn(&mut T, &Bar),
    );
}

Note how the callback no longer needs to be unsafe (since it doesn't take raw pointers)!
An adapter for a closure being used as the callback can be as simple as:

extern "C" fn callback(f: &mut impl FnMut(&Bar), bar: &Bar) {
    f(bar);
}

(or even just |f, bar| f(bar) if we start coercing closures to non-Rust-ABI fn pointers)

cc @rust-lang/compiler

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

No source files or tests are named in the issue. Start by tracing Rust compiler handling of FFI imports, generic parameters, and ABI/layout computation; define completion as accepting sized ABI-agnostic generics while rejecting cases such as <T: ?Sized> that require type-dependent layout.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.