Summary

Unify std::os::raw::c_void and libc::c_void by making them both re-exports of a definition

定義
in libcore.

Motivation

std::os::raw::c_void and libc::c_void are different types:

#![allow(unused)] fn main() { extern crate libc; fn allocate_something() -> *mut std::os::raw::c_void { unimplemented!() } fn foo() { let something = allocate_something(); // ... libc::free(something) } }
#![allow(unused)] fn main() { error[E0308]: mismatched types --> a.rs:10:16 | 10 | libc::free(something) | ^^^^^^^^^ expected enum `libc::c_void`, found enum `std::os::raw::c_void` | = note: expected type `*mut libc::c_void` found type `*mut std::os::raw::c_void` error: aborting due to previous error }

There is no good reason for this, the program above should compile.

Note that having separate definitions

定義
is not as much of a problem for other c_* types since they are type aliases.
別名
c_int is i32 for example, and separate aliases
別名
with identical
同一の(である)
definitions
定義
are compatible with each other in the type system. c_void however is currently defined
定義する
as an enum (of size 1 byte, with semi-private variants), and two enum types with identical
同一の(である)
definitions
定義
are still different types.

This has been extensively discussed already:

Guide-level explanation

With this RFC implemented

実装する
in both the standard library and in the libc crate, std::os::raw::c_void and libc::c_void are now two ways to name the same type.

If two independent libraries both provide

与える
FFI bindings to C functions that involve void* pointers, one might use std while the other uses libc to access the c_void type in order
順序
to expose *mut c_void in their respective
それぞれの
public APIs. A pointer returned from one library can now be passed to the other library without an as pointer cast.

#![no_std] crates can now also access that same type at core::ffi::c_void.

Reference-level explanation

In the standard library:

  • Create a new core::ffi module.
  • Move the enum definiton of c_void there.
  • In c_void’s former location (std::os::raw), replace it with a pub use reexport.
  • For consistency between core and std, also add a similar
    似ている、同様の
    pub use reexport at std::ffi::c_void. (Note that the std::ffi module already exists.)

Once the above lands in Nightly, in the libc crate:

  • Add a build script that detects the existence of core::ffi::c_void (for example by executing
    実行(する)
    $RUSTC with a temporary
    一時的な
    file like #![crate_type = "lib"] #![no_std] pub use core::ffi::c_void;) and conditionally set
    セットする、集合
    a compilation flag for the library.
  • In the library, based
    基となる、基底(の)
    on the precence of that flag, make c_void be either pub use core::ffi::c_void; or its current enum definition,
    定義
    to keep compatibility
    互換性
    with older Rust versions.

Drawbacks

This proposal is a breaking change for users who implement

実装する
a trait of theirs like this:

#![allow(unused)] fn main() { trait VoidPointerExt {…} impl VoidPointerExt for *mut std::os::raw::c_void {…} impl VoidPointerExt for *mut libc::c_void {…} }

With the two c_void types being unified, the two impls would overlap

重なる/重なり
and fail to compile.

Hopefully such breakage is rare

まれ
enough that we can manage it. Rarity could be evaluated
評価する(される)
with Crater by either:

  • Adding

    たす
    support to Crater if it doesn’t have it already for adding
    たす
    a [patch.crates-io] section
    to each root Cargo.toml being tested, in order
    順序
    to test with a patched libc crate in addition
    追加
    to a patched Rust.

  • Or speculatively landing the changes in libc and publishing them in crates.io before landing them in Rust

Rationale and alternatives
代わりのもの、選択肢

libc cannot reexport std::os::raw::c_void because this would regress compatibility

互換性
with #![no_std].

RFC #1783 proposed adding

たす
to the standard library distribution a new crate specifically
特に
for the C-compatible types. Both std and libc would depend on this crate.

This was apparently in response to reluctance about having operating-system-dependant definitions

定義
(such as for c_long) in libcore. This concern does not apply
適用する
to c_void, whose definition
定義
is the same regardless
〜に関わらず
of the target. However there was also reluctance to having an entire crate for so little functionality.

That RFC was closed / postponed with this explanation:

The current consensus is to offer a canonical way of producing

産出、産出する
an "unknown, opaque type" (a better c_void), possible along the lines of #1861

RFC 1861 for extern types is now being implemented,

実装する
but those types are !Sized. Changing c_void from Sized to !Sized would be a significant breaking change: for example, ptr::null::<c_void>() and <*mut c_void>::offset(n) would not be usable anymore.

We could deprecated c_void and replace it with a new differently-named extern type, but forcing the ecosystem through that transition seems too costly for this theoretical nicety. Plus, this woud still be a nominal type. If this new type is to be present

ある
if both libc and std, it would still have to be in core as well.

Unresolved questions

What is the appropriate location for c_void in libcore?

This RFC proposes core::ffi rather than core::os::raw on the basis that C-compatible types are misplaced in std::os::raw. std::os is documented

文書
as “OS-specific functionality”, but everything currently available under std::os::raw is about interoperabily with C rather than operating system functionality. (Although the exact definition
定義
of c_char, c_long, and c_ulong does vary based
基となる、基底(の)
on the target operating system.) FFI stands for Foreign Function Interface and is about calling
呼び出し
or being called
呼び出し
from functions in other languages
言語
such as C. So the ffi module seems more appropriate than os for C types, and it already exists in std.

Following

下記の、次に続く、追従する
this logic to this conclusion, perhaps the rest of std::os::raw should also move to std::ffi as well, and the former module be deprecated eventually. This is left for a future RFC.

This RFC does not propose any change such as moving to libcore for the C types other than c_void.

Although some in previous

前の
discussions have expressed desire for using C-compatible types without linking to the C runtime libray (which the libc crate does) or depending on std. This use case is also left for a future proposal or RFC.