Skip to content

Commit 9bb8d58

Browse files
authored
Merge pull request #2521 from SimonSapin/無
Unify std::os::raw::c_void and libc::c_void via libcore
2 parents d5e8e7b + 41755b3 commit 9bb8d58

File tree

1 file changed

+180
-0
lines changed

1 file changed

+180
-0
lines changed

text/0000-c_void-reunification.md

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
- Feature Name: c_void-reunification
2+
- Start Date: 2018-08-02
3+
- RFC PR: (leave this empty)
4+
- Rust Issue: (leave this empty)
5+
6+
# Summary
7+
[summary]: #summary
8+
9+
Unify `std::os::raw::c_void` and `libc::c_void` by making them both re-exports
10+
of a definition in libcore.
11+
12+
13+
# Motivation
14+
[motivation]: #motivation
15+
16+
`std::os::raw::c_void` and `libc::c_void` are different types:
17+
18+
```rust
19+
extern crate libc;
20+
21+
fn allocate_something() -> *mut std::os::raw::c_void {
22+
unimplemented!()
23+
}
24+
25+
fn foo() {
26+
let something = allocate_something();
27+
// ...
28+
libc::free(something)
29+
}
30+
```
31+
```rust
32+
error[E0308]: mismatched types
33+
--> a.rs:10:16
34+
|
35+
10 | libc::free(something)
36+
| ^^^^^^^^^ expected enum `libc::c_void`, found enum `std::os::raw::c_void`
37+
|
38+
= note: expected type `*mut libc::c_void`
39+
found type `*mut std::os::raw::c_void`
40+
41+
error: aborting due to previous error
42+
```
43+
44+
There is no good reason for this, the program above should compile.
45+
46+
Note that having separate definitions is not as much of a problem for other `c_*` types
47+
since they are `type` aliases. `c_int` *is* `i32` for example,
48+
and separate aliases with identical definitions are compatible with each other in the type system.
49+
`c_void` however is currently defined as an `enum` (of size 1 byte, with semi-private variants),
50+
and two `enum` types with identical definitions are still different types.
51+
52+
This has been extensively discussed already:
53+
54+
* [Issue #31536: std `c_void` and libc `c_void` are different types](https://github.com/rust-lang/rust/issues/31536)
55+
* [Internals #3268: Solve `std::os::raw::c_void`](https://internals.rust-lang.org/t/solve-std-os-raw-c-void/3268)
56+
* [Issue #36193: Move std::os::raw to libcore?](https://github.com/rust-lang/rust/issues/36193)
57+
* [RFC #1783: Create a separate libc_types crate for basic C types](https://github.com/rust-lang/rfcs/pull/1783)
58+
* [Issue #47027: Types in std::os::raw should be same as libc crate](https://github.com/rust-lang/rust/issues/47027)
59+
* [Internals #8086: Duplicate std::os::raw in core?](https://internals.rust-lang.org/t/duplicate-std-raw-in-core/8086)
60+
* [PR #52839: Move std::os::raw into core](https://github.com/rust-lang/rust/pull/52839)
61+
62+
63+
# Guide-level explanation
64+
[guide-level-explanation]: #guide-level-explanation
65+
66+
With this RFC implemented in both the standard library and in the `libc` crate,
67+
`std::os::raw::c_void` and `libc::c_void` are now two ways to name the same type.
68+
69+
If two independent libraries both provide FFI bindings to C functions that involve `void*` pointers,
70+
one might use `std` while the other uses `libc` to access the `c_void` type in order to expose
71+
`*mut c_void` in their respective public APIs.
72+
A pointer returned from one library can now be passed to the other library without an `as` pointer cast.
73+
74+
`#![no_std]` crates can now also access that same type at `core::ffi::c_void`.
75+
76+
77+
# Reference-level explanation
78+
[reference-level-explanation]: #reference-level-explanation
79+
80+
In the standard library:
81+
82+
* Create a new `core::ffi` module.
83+
* Move the `enum` definiton of `c_void` there.
84+
* In `c_void`’s former location (`std::os::raw`), replace it with a `pub use` reexport.
85+
* For consistency between `core` and `std`, also add a similar `pub use` reexport at `std::ffi::c_void`.
86+
(Note that the `std::ffi` module already exists.)
87+
88+
Once the above lands in Nightly, in the `libc` crate:
89+
90+
* Add a build script that detects the existence of `core::ffi::c_void`
91+
(for example by executing `$RUSTC` with a temporary file like
92+
`#![crate_type = "lib"] #![no_std] pub use core::ffi::c_void;`)
93+
and conditionally set a compilation flag for the library.
94+
* In the library, based on the precence of that flag,
95+
make `c_void` be either `pub use core::ffi::c_void;` or its current `enum` definition,
96+
to keep compatibility with older Rust versions.
97+
98+
99+
# Drawbacks
100+
[drawbacks]: #drawbacks
101+
102+
This proposal is a breaking change for users who implement a trait of theirs like this:
103+
104+
```rust
105+
trait VoidPointerExt {…}
106+
impl VoidPointerExt for *mut std::os::raw::c_void {…}
107+
impl VoidPointerExt for *mut libc::c_void {…}
108+
```
109+
110+
With the two `c_void` types being unified, the two `impl`s would overlap and fail to compile.
111+
112+
Hopefully such breakage is rare enough that we can manage it.
113+
Rarity could be evaluated with Crater by either:
114+
115+
* Adding support to Crater if it doesn’t have it already
116+
for adding a `[patch.crates-io]` section to each root `Cargo.toml` being tested,
117+
in order to test with a patched `libc` crate in addition to a patched Rust.
118+
119+
* Or speculatively landing the changes in `libc` and publishing them in crates.io
120+
before landing them in Rust
121+
122+
123+
# Rationale and alternatives
124+
[rationale-and-alternatives]: #rationale-and-alternatives
125+
126+
`libc` cannot reexport `std::os::raw::c_void`
127+
because this would regress compatibility with `#![no_std]`.
128+
129+
[RFC #1783](https://github.com/rust-lang/rfcs/pull/1783) proposed adding
130+
to the standard library distribution a new crate specifically for the C-compatible types.
131+
Both `std` and `libc` would depend on this crate.
132+
133+
This was apparently in response to reluctance about having operating-system-dependant definitions
134+
(such as for `c_long`) in libcore.
135+
This concern does not apply to `c_void`, whose definition is the same regardless of the target.
136+
However there was also reluctance to having an entire crate for so little functionality.
137+
138+
That RFC was closed / postponed with this explanation:
139+
140+
> The current consensus is to offer a canonical way of producing
141+
> an "unknown, opaque type" (a better c_void), possible along the lines of
142+
> [#1861](https://github.com/rust-lang/rfcs/pull/1861)
143+
144+
RFC 1861 for `extern` types is now being implemented, but those types are `!Sized`.
145+
Changing `c_void` from `Sized` to `!Sized` would be a significant breaking change:
146+
for example, `ptr::null::<c_void>()` and `<*mut c_void>::offset(n)` would not be usable anymore.
147+
148+
We could deprecated `c_void` and replace it with a new differently-named extern type,
149+
but forcing the ecosystem through that transition seems too costly for this theoretical nicety.
150+
Plus, this woud still be a nominal type.
151+
If this new type is to be present if both `libc` and `std`,
152+
it would still have to be in `core` as well.
153+
154+
155+
# Unresolved questions
156+
[unresolved-questions]: #unresolved-questions
157+
158+
What is the appropriate location for `c_void` in libcore?
159+
160+
This RFC proposes `core::ffi` rather than `core::os::raw`
161+
on the basis that C-compatible types are misplaced in `std::os::raw`.
162+
`std::os` is documented as “OS-specific functionality”,
163+
but everything currently available under `std::os::raw` is about interoperabily with C
164+
rather than operating system functionality.
165+
(Although the exact definition of `c_char`, `c_long`, and `c_ulong` does vary
166+
based on the target operating system.)
167+
FFI stands for Foreign Function Interface and is about calling or being called from functions
168+
in other languages such as C.
169+
So the `ffi` module seems more appropriate than `os` for C types, and it already exists in `std`.
170+
171+
Following this logic to this conclusion,
172+
perhaps the rest of `std::os::raw` should also move to `std::ffi` as well,
173+
and the former module be deprecated eventually.
174+
This is left for a future RFC.
175+
176+
This RFC does not propose any change such as moving to libcore for the C types other than `c_void`.
177+
178+
Although some in previous discussions have expressed desire for using C-compatible types
179+
without linking to the C runtime libray (which the `libc` crate does) or depending on `std`.
180+
This use case is also left for a future proposal or RFC.

0 commit comments

Comments
 (0)