-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
Remove confusing comment about ideally using !
for c_void
#56594
Conversation
r? @TimNN (rust_highfive has picked a reviewer for you, use r? to override) |
This might be something @RalfJung could know and clarify :) |
Maybe. That's not decided yet (and I think it shouldn't be). But |
So concerning this PR, I basically agree with this change, but there are some comments here that are still dangerously misleading. Namely, the comments say that the two variants shouldn't have to exist. But that would be fatal! An enum with no variants behaves exactly like So the non-doc-comments here should also be fixed to explain that we need at least one variant to avoid UB.
Cc @gankro The nomicon pattern is designed to avoid the non-FFI-safe-types warning. Does this enum also avoid that? |
Thanks a lot for the clarifications!
Thanks, I've updated the comment and
Ok, intuitively it would seem like such references should never exist similar to how references to
There don't seem to be any warnings, no. See https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=7c3c81c0b724dafbb2ed11d6ee943697 use std::ffi::c_void;
pub struct Foo(c_void);
pub extern "C" fn meh1(m: *mut Foo) -> *mut Foo { m }
#[repr(C)]
pub struct Bar {
v: *mut Foo,
}
pub extern "C" fn meh2(m: *mut Bar) -> *mut Bar { m } |
No, references must never be NULL. That's part of their validity invariant.
Uninhabitedness is not a special property when it comes to UB. I think "is having a
That's great! @SimonSapin do you remember why you suggested this empty-array pattern in rust-lang/nomicon#44 instead of a newtype around |
Actually, it seems there never are warnings for exporting functions. But this also does not warn (we do need the use std::ffi::c_void;
#[repr(C)]
pub struct Foo(c_void);
extern "C" {
fn meh1(m: *mut Foo) -> *mut Foo;
} |
To avoid uninhabited types, it seemed like a zero-size type would be the next closest thing. To avoid some misuses this type should not be trivial to construct, so it should have a private field.
|
That would fit in a one-liner. |
(gonna assume Simon has this issue covered) |
Why is the
Is passing of ZST over FFI well-defined? A pointer to one, sure Is there any advantage for having a ZST here over |
Ah right, the point was to make it a ZST! Thanks for reminding me.
Yes: If you ever accidentally dereference the pointer, it's a NOP if it points to a ZST. |
Yes, that was the point but I’m not sure how important it is. When a type does not implement any trait (in particular not |
Ok, that makes sense but also doesn't really make a difference in practice compared to reading a byte or does it? Unless it was an dangling pointer but in that case... So I guess,
|
Given that this is a pointer to an opaque type, the opaque type might have size 0, and in that case the read would be a problem.
I think this PR is an improvement over the status quo certainly, and as such I'm in favor of landing it. However, it'd be nice to be consistent with the FFI section in the nomicon -- we should recommend the same thing for the same job. So, I'd prefer if instead of recommending to use this for opaque extern types, it would point to the nomicon.
Yes. Struct field ordering otherwise may differ between C and Rust (and even between different Rust versions).
I'd prefer to keep recommending the empty array. Eventually (TM), we'll have extern types and then the answer about what to use is quite clear. |
Thanks for the clarifications :)
But as this is an opaque type we don't even know its fields. That was my point, you only have a pointer of reference but don't know what's behind it anyway.
OK, I'll update it accordingly later and also add a link to the Thanks again for all the explanations :) |
Updated |
392db0f
to
7a4d32f
Compare
I guess then it strictly speaking doesn't matter. But there also is no reason not to use |
Sure, this was just to complete my understanding. I agree that marking things as |
Using `!` for `c_void` would have the problem that pointers and potentially references to an uninhabited type would be created, and at least for references this is UB. Also document in addition that newtype wrappers around `c_void` are not recommended for representing opaque types (as a workaround for `extern type` not being stable) but instead refer to the Nomicon.
…rent implementation We need at least two variants of the enum as otherwise the compiler complains about the #[repr(u8)] attribute and we also need at least one variant as otherwise the enum would be uninhabitated and dereferencing pointers to it would be UB. As such, mark the variants not unstable because they should not actually exist but because they are temporary implementation details until `extern type` is stable and can be used instead.
7a4d32f
to
8de8880
Compare
This patch looks good to me now. @SimonSapin what do you think? |
The diff says Note that |
The idea was that it could be replaced with
Moving
And this documentation/comments update here would bring all these things in sync again. However your point about |
I assume we didn’t realize the |
also extern types have been stalled precisely because how size is supposed to work was punted on, and no one can agree on how to proceed |
I see, I didn't realize that this is still an open issue. So what to do here then? Feel free to simply close the PR if you think there's no value in this before everything else is cleared up elsewhere. IMHO |
I've read some of the discussion and skimmed the rest. Overall I think the new docs are an improvement over the old ones, so: @bors r+ (If someone disagrees, please comment / |
📌 Commit 8de8880 has been approved by |
@bors rollup |
Remove confusing comment about ideally using `!` for `c_void` Using `!` for `c_void` would have the problem that pointers and potentially references to an uninhabited type would be created, and at least for references this is UB. In addition document that newtype wrappers around `c_void` can be used safely in place of `extern type` until the latter is stabilized. ---- I'm not 100% sure about the usage for opaque types as the [nomicon](https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs) still recommends using `#[repr(C)] pub struct Foo { _private: [u8; 0] }` but it seems like these two should be equivalent in the end? Also the `#[repr(C)]` (in both cases) should be unneeded because such types never being passed by value, never being dereferenced but only passed around as pointer or reference, so the representation of (*values* of) the type itself should not matter at all? Also in context of `c_void` and `!` the second unresolved question in the [`extern type`](rust-lang#43467) stabilization ticket seems relevant > In [std's](https://github.com/rust-lang/rust/blob/164619a8cfe6d376d25bd3a6a9a5f2856c8de64d/src/libstd/os/raw.rs#L59-L64) source, it is mentioned that LLVM expects i8* for C's void*. > We'd need to continue to hack this for the two c_voids in std and libc. > But perhaps this should be done across-the-board for all extern types? > Somebody should check what Clang does. Please correct me if my understanding is wrong and everything's actually fine as is.
Remove confusing comment about ideally using `!` for `c_void` Using `!` for `c_void` would have the problem that pointers and potentially references to an uninhabited type would be created, and at least for references this is UB. In addition document that newtype wrappers around `c_void` can be used safely in place of `extern type` until the latter is stabilized. ---- I'm not 100% sure about the usage for opaque types as the [nomicon](https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs) still recommends using `#[repr(C)] pub struct Foo { _private: [u8; 0] }` but it seems like these two should be equivalent in the end? Also the `#[repr(C)]` (in both cases) should be unneeded because such types never being passed by value, never being dereferenced but only passed around as pointer or reference, so the representation of (*values* of) the type itself should not matter at all? Also in context of `c_void` and `!` the second unresolved question in the [`extern type`](rust-lang#43467) stabilization ticket seems relevant > In [std's](https://github.com/rust-lang/rust/blob/164619a8cfe6d376d25bd3a6a9a5f2856c8de64d/src/libstd/os/raw.rs#L59-L64) source, it is mentioned that LLVM expects i8* for C's void*. > We'd need to continue to hack this for the two c_voids in std and libc. > But perhaps this should be done across-the-board for all extern types? > Somebody should check what Clang does. Please correct me if my understanding is wrong and everything's actually fine as is.
Remove confusing comment about ideally using `!` for `c_void` Using `!` for `c_void` would have the problem that pointers and potentially references to an uninhabited type would be created, and at least for references this is UB. In addition document that newtype wrappers around `c_void` can be used safely in place of `extern type` until the latter is stabilized. ---- I'm not 100% sure about the usage for opaque types as the [nomicon](https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs) still recommends using `#[repr(C)] pub struct Foo { _private: [u8; 0] }` but it seems like these two should be equivalent in the end? Also the `#[repr(C)]` (in both cases) should be unneeded because such types never being passed by value, never being dereferenced but only passed around as pointer or reference, so the representation of (*values* of) the type itself should not matter at all? Also in context of `c_void` and `!` the second unresolved question in the [`extern type`](rust-lang#43467) stabilization ticket seems relevant > In [std's](https://github.com/rust-lang/rust/blob/164619a8cfe6d376d25bd3a6a9a5f2856c8de64d/src/libstd/os/raw.rs#L59-L64) source, it is mentioned that LLVM expects i8* for C's void*. > We'd need to continue to hack this for the two c_voids in std and libc. > But perhaps this should be done across-the-board for all extern types? > Somebody should check what Clang does. Please correct me if my understanding is wrong and everything's actually fine as is.
Remove confusing comment about ideally using `!` for `c_void` Using `!` for `c_void` would have the problem that pointers and potentially references to an uninhabited type would be created, and at least for references this is UB. In addition document that newtype wrappers around `c_void` can be used safely in place of `extern type` until the latter is stabilized. ---- I'm not 100% sure about the usage for opaque types as the [nomicon](https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs) still recommends using `#[repr(C)] pub struct Foo { _private: [u8; 0] }` but it seems like these two should be equivalent in the end? Also the `#[repr(C)]` (in both cases) should be unneeded because such types never being passed by value, never being dereferenced but only passed around as pointer or reference, so the representation of (*values* of) the type itself should not matter at all? Also in context of `c_void` and `!` the second unresolved question in the [`extern type`](rust-lang#43467) stabilization ticket seems relevant > In [std's](https://github.com/rust-lang/rust/blob/164619a8cfe6d376d25bd3a6a9a5f2856c8de64d/src/libstd/os/raw.rs#L59-L64) source, it is mentioned that LLVM expects i8* for C's void*. > We'd need to continue to hack this for the two c_voids in std and libc. > But perhaps this should be done across-the-board for all extern types? > Somebody should check what Clang does. Please correct me if my understanding is wrong and everything's actually fine as is.
Remove confusing comment about ideally using `!` for `c_void` Using `!` for `c_void` would have the problem that pointers and potentially references to an uninhabited type would be created, and at least for references this is UB. In addition document that newtype wrappers around `c_void` can be used safely in place of `extern type` until the latter is stabilized. ---- I'm not 100% sure about the usage for opaque types as the [nomicon](https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs) still recommends using `#[repr(C)] pub struct Foo { _private: [u8; 0] }` but it seems like these two should be equivalent in the end? Also the `#[repr(C)]` (in both cases) should be unneeded because such types never being passed by value, never being dereferenced but only passed around as pointer or reference, so the representation of (*values* of) the type itself should not matter at all? Also in context of `c_void` and `!` the second unresolved question in the [`extern type`](rust-lang#43467) stabilization ticket seems relevant > In [std's](https://github.com/rust-lang/rust/blob/164619a8cfe6d376d25bd3a6a9a5f2856c8de64d/src/libstd/os/raw.rs#L59-L64) source, it is mentioned that LLVM expects i8* for C's void*. > We'd need to continue to hack this for the two c_voids in std and libc. > But perhaps this should be done across-the-board for all extern types? > Somebody should check what Clang does. Please correct me if my understanding is wrong and everything's actually fine as is.
Remove confusing comment about ideally using `!` for `c_void` Using `!` for `c_void` would have the problem that pointers and potentially references to an uninhabited type would be created, and at least for references this is UB. In addition document that newtype wrappers around `c_void` can be used safely in place of `extern type` until the latter is stabilized. ---- I'm not 100% sure about the usage for opaque types as the [nomicon](https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs) still recommends using `#[repr(C)] pub struct Foo { _private: [u8; 0] }` but it seems like these two should be equivalent in the end? Also the `#[repr(C)]` (in both cases) should be unneeded because such types never being passed by value, never being dereferenced but only passed around as pointer or reference, so the representation of (*values* of) the type itself should not matter at all? Also in context of `c_void` and `!` the second unresolved question in the [`extern type`](rust-lang#43467) stabilization ticket seems relevant > In [std's](https://github.com/rust-lang/rust/blob/164619a8cfe6d376d25bd3a6a9a5f2856c8de64d/src/libstd/os/raw.rs#L59-L64) source, it is mentioned that LLVM expects i8* for C's void*. > We'd need to continue to hack this for the two c_voids in std and libc. > But perhaps this should be done across-the-board for all extern types? > Somebody should check what Clang does. Please correct me if my understanding is wrong and everything's actually fine as is.
Remove confusing comment about ideally using `!` for `c_void` Using `!` for `c_void` would have the problem that pointers and potentially references to an uninhabited type would be created, and at least for references this is UB. In addition document that newtype wrappers around `c_void` can be used safely in place of `extern type` until the latter is stabilized. ---- I'm not 100% sure about the usage for opaque types as the [nomicon](https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs) still recommends using `#[repr(C)] pub struct Foo { _private: [u8; 0] }` but it seems like these two should be equivalent in the end? Also the `#[repr(C)]` (in both cases) should be unneeded because such types never being passed by value, never being dereferenced but only passed around as pointer or reference, so the representation of (*values* of) the type itself should not matter at all? Also in context of `c_void` and `!` the second unresolved question in the [`extern type`](rust-lang#43467) stabilization ticket seems relevant > In [std's](https://github.com/rust-lang/rust/blob/164619a8cfe6d376d25bd3a6a9a5f2856c8de64d/src/libstd/os/raw.rs#L59-L64) source, it is mentioned that LLVM expects i8* for C's void*. > We'd need to continue to hack this for the two c_voids in std and libc. > But perhaps this should be done across-the-board for all extern types? > Somebody should check what Clang does. Please correct me if my understanding is wrong and everything's actually fine as is.
Rollup of 10 pull requests Successful merges: - #56594 (Remove confusing comment about ideally using `!` for `c_void`) - #57340 (Use correct tracking issue for c_variadic) - #57357 (Cleanup PartialEq docs.) - #57551 (resolve: Add a test for issue #57539) - #57636 (Fix sources sidebar not showing up) - #57646 (Fixes text becoming invisible when element targetted) - #57654 (Add some links in std::fs.) - #57683 (Document Unpin in std::prelude documentation) - #57685 (Enhance `Pin` impl applicability for `PartialEq` and `PartialOrd`.) - #57710 (Fix non-clickable urls) Failed merges: r? @ghost
Using
!
forc_void
would have the problem that pointers andpotentially references to an uninhabited type would be created, and at
least for references this is UB.
In addition document that newtype wrappers around
c_void
can be usedsafely in place of
extern type
until the latter is stabilized.I'm not 100% sure about the usage for opaque types as the nomicon still recommends using
#[repr(C)] pub struct Foo { _private: [u8; 0] }
but it seems like these two should be equivalent in the end? Also the#[repr(C)]
(in both cases) should be unneeded because such types never being passed by value, never being dereferenced but only passed around as pointer or reference, so the representation of (values of) the type itself should not matter at all?Also in context of
c_void
and!
the second unresolved question in theextern type
stabilization ticket seems relevantPlease correct me if my understanding is wrong and everything's actually fine as is.