Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow "ABI agnostic" generics in FFI imports. #2770

Open
eddyb opened this issue Sep 8, 2018 · 5 comments
Open

Allow "ABI agnostic" generics in FFI imports. #2770

eddyb opened this issue Sep 8, 2018 · 5 comments
Labels
A-ffi FFI related proposals. T-lang Relevant to the language team, which will review and decide on the RFC.

Comments

@eddyb
Copy link
Member

eddyb commented Sep 8, 2018

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

@strega-nil
Copy link

This seems like a good idea.

@rpjohnst
Copy link

rpjohnst commented Sep 8, 2018

I would love to have this sort of thing outside the context of FFI as well- a way to write generic code that's guaranteed not to be monomorphized because it's just passing around pointers.

@eddyb
Copy link
Member Author

eddyb commented Sep 8, 2018

@rpjohnst That's a separate problem, rust-lang/rust#46477 (which should probably be renamed).
While FFI only cares about enforcing the call ABI doesn't depend on generic parameters, Rust functions with bodies need to have "parameter independence" found by analysis, and then codegen needs to be able to handle unsubstituted parameters (which would currently probably ICE a lot).

@eddyb eddyb changed the title Allow "ABI irrelevant" generics in FFI imports. Allow "ABI agnostic" generics in FFI imports. Sep 24, 2018
@Mark-Simulacrum Mark-Simulacrum transferred this issue from rust-lang/rust Sep 22, 2019
@Centril Centril added A-ffi FFI related proposals. T-lang Relevant to the language team, which will review and decide on the RFC. labels Sep 22, 2019
@comex
Copy link

comex commented Sep 22, 2019

(Saw this for the first time when I got an email notification due to it being transferred to the RFCs repo, so here's a reply to a year-old comment...)

@rpjohnst That's a separate problem, rust-lang/rust#46477 (which should probably be renamed).
While FFI only cares about enforcing the call ABI doesn't depend on generic parameters, Rust functions with bodies need to have "parameter independence" found by analysis, and then codegen needs to be able to handle unsubstituted parameters (which would currently probably ICE a lot).

I somewhat disagree. An optimization pass that discovers functions that happen to be "parameter independent" would be nice to have, but I'd also like a language feature to enforce independence at the source level. This would be useful as a way to control compile time and code size. And it would also allow such parameters to be object safe.

@eddyb
Copy link
Member Author

eddyb commented Sep 26, 2019

@comex Fair, although that sounds a bit more like the fn foo<dyn T: Foo>(x: &T) {...} feature @nikomatsakis brings up sometimes (being able to refer to the type but trait dispatch being dynamic, a bit like Haskell/Java generics), which is a bit more involved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-ffi FFI related proposals. T-lang Relevant to the language team, which will review and decide on the RFC.
Projects
None yet
Development

No branches or pull requests

5 participants