Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upTransparent Unions and Enums #2645
Conversation
mjbshaw
changed the title
Transparent Unions RFC
Transparent Unions
Feb 25, 2019
Centril
added
T-lang
A-repr
A-unions
labels
Feb 25, 2019
Centril
reviewed
Feb 25, 2019
text/0000-transparent-unions.md Outdated
text/0000-transparent-unions.md Outdated
text/0000-transparent-unions.md Outdated
text/0000-transparent-unions.md Outdated
text/0000-transparent-unions.md Outdated
text/0000-transparent-unions.md Outdated
text/0000-transparent-unions.md Outdated
text/0000-transparent-unions.md Outdated
text/0000-transparent-unions.md Outdated
Centril
and others
added some commits
Feb 25, 2019
This comment has been minimized.
This comment has been minimized.
|
Thanks for the review, @Centril! I'm still working on getting to those last remaining items you mentioned, but in the meantime I implemented the feature (including for univariant enums). It probably needs some fixing, and definitely needs some tests, but it can serve as a starting point for what the feature might look like in real life. |
mjbshaw
changed the title
Transparent Unions
Transparent Unions and Enums
Feb 27, 2019
Centril
added
the
A-enum
label
Feb 27, 2019
mjbshaw
added some commits
Feb 27, 2019
This comment has been minimized.
This comment has been minimized.
|
The points I raised IMO show that this optimization is NOT sound today -- LLVM can produce code that passes indeterminate values as argument e.g. during uninlining. Also, I'd be very cautious about optimizations of this style. There's no consensus for how indeterminate values behave inside a C program, let alone how they pass across linking. |
This comment has been minimized.
This comment has been minimized.
|
So, to be clear: IMO Now, you say it is impossible to write a function in C that actually can take a |
This comment has been minimized.
This comment has been minimized.
|
re: passing uninitalized data through FFI, I agree that it is not automatically UB (@gnzlbg when we were talking on Discord earlier today, I believe I said otherwise, sorry for the brainfart). However, it is an extremely niche and minor optimizations, and it depends on a ton of detailed and brittle knowledge of the C side of things to be able to justify it. Plus, even in other languages where certain uses of uninitalized data are not immediate UB it is still most likely very easy to get UB from them, so you still need to audit exactly what the callee is doing with the argument. So if this is the only reason why someone would want to pass a That leaves the question of memory layout compatibility. @mjbshaw has explained sufficiently why they have a preference for guaranteeing this layout compatibility by first adding Instead I only want to highlight that Disclaimer: it's obvious that I personally do not want this RFC merged, but of course I would accept if the consensus was to merge. I just think that it's very likely some people ticked their boxes under a wrong impression of the benefits of this RFC. |
This comment has been minimized.
This comment has been minimized.
|
So I talked with @RalfJung for a while about this on Zulip. I apologize. I was incorrectly reading So basically, when I said above that something is UB, it is only UB if the code at the other side of the FFI is actually C. That is, code like this extern "C" { fn foo() -> MaybeUninit<u32>; }
let x = unsafe { foo() };is useful and has defined behavior, it is just not code that one would write to interface with actual C (sorry @mjbshaw I think I was talking past you on this issue in some of the other comments). |
This comment has been minimized.
This comment has been minimized.
|
The discussion about optimizations are a bit orthogonal to the rest, but when @RalfJung mentioned:
I think it is worth mentioning that while this optimization is not sound for all FFI code, it is sound for C as well as for Rust code interfacing with C. This is a major use case of Rust FFI. |
This comment has been minimized.
This comment has been minimized.
Either some guarantees would have to be made about all
I don't think the picture has changed. @RalfJung even called this out explicitly before this RFC was written (bold emphasis mine):
People already knew that One advantage I see to |
This comment has been minimized.
This comment has been minimized.
As I said before, we can achieve memory layout compatibility without any special casing or language features by marking
That is not the change I was referring to (indeed it's not a change as you say). Instead, the aspect that was new in my opinion is that the use cases people actively argue for don't need ABI compatibility at all. If ABI compatibility was needed for something, ... at least, until @gnzlbg pointed out to me on Discord that Rust-Rust communication can quite plausibly also happen through a C ABI (e.g., to get dynamic linking). While we still don't have a concrete example of real code needing this, it's a plausible enough sketch that I no longer want to claim that there are no use cases for transparent unions. Consider my objection to the FCP withdrawn. I'm still unconvinced by the arguments laid out in the RFC text and in this discussion, but it's good enough for me that I don't want to die on this hill. |
This comment has been minimized.
This comment has been minimized.
|
@rfcbot concern how-important-is-this I am raising this concern to echo @rkruppe's post here. I've not been able to follow this discussion in detail, but they make a fairly convincing case to me that we should think twice here! (@rkruppe, if you feel this is resolved, let me know and I will lift the concern.) |
rfcbot
added
proposed-final-comment-period
and removed
final-comment-period
labels
Mar 20, 2019
This comment has been minimized.
This comment has been minimized.
|
Er, heh, I see the last paragraph of @rkruppe's post says this:
I'm going to go ahead and resolve the concern for now, but I .. hmm. Yeah, I think I still have some concerns, but it's probably about me not understanding deeply enough. I think I'll probably wind up coming to understand this better though as we incorporate some of this text into the UCG guidelines. @rfcbot resolve how-important-is-this This raises an interesting procedural question: I think that, going forward, RFCs like this should really be "executed" as part of the @rust-lang/wg-unsafe-code-guidelines process, and we should think about how that should work. But it's not a topic we have to discuss at this moment. |
rfcbot
added
final-comment-period
and removed
proposed-final-comment-period
labels
Mar 20, 2019
This comment has been minimized.
This comment has been minimized.
rfcbot
commented
Mar 20, 2019
|
|
This comment has been minimized.
This comment has been minimized.
|
FWIW I consider that use case a very long stretch of our imagination about what this RFC could be useful for. We explored many use-cases for a long time on Discord, and all of them could be solved by just guaranteeing the layout of these unions. The Rust-Rust C FFI dynamic library case was what we invented to justify this, but you need to control Rust code at both sides to make it work, and if that's the case, why aren't you using the Rust ABI ? There might be good arguments for that, but I would prefer if this RFC was put on hold until we merge an RFC guaranteeing layout for these types first, and then see what value would this add on top of that. |
This comment has been minimized.
This comment has been minimized.
|
@gnzlbg The Rust calling convention is unstable, so the C calling convention (or others not defined by rustc) are your only choice if you want to link together two pieces of Rust compiled with different compiler versions. Most Rust types don't have a stable ABI either, so you can't use them in those interfaces, but |
This comment has been minimized.
This comment has been minimized.
@gnzlbg Note that if/when this RFC is merged the actual implementation will go through the usual stabilization process. If you want to file an RFC you will have plenty of time to do so. |
This comment has been minimized.
This comment has been minimized.
@rkruppe my point was that for the Rust-Rust dynamic lib over C FFI to work you kind of have to been in control of the Rust code on both places to make sure they make use over the right Rust types (if they only assume the code at the other side of the ABI is C then none of this applies). That is, if you are in control of the Rust code at both sides, you can often compile it with the same compiler version. Sure, this is not always the case, but it feels like if.. if.. if.. if.. then this is useful, which is what i mean by a stretch. |
This comment has been minimized.
This comment has been minimized.
vi
commented
Mar 21, 2019
•
|
Shall this be allowed?: #[repr(transparent)]
enum StaringIntoTheVoid {
Empty(!),
Lifeline(i32),
DoublyNothing(!,!),
}
What is interaction between |
This comment has been minimized.
This comment has been minimized.
|
@vi Interesting, I hadn't thought of that case. Currently the plan is to allow only single-variant |
This comment has been minimized.
This comment has been minimized.
vi
commented
Mar 21, 2019
•
Obviously, the same as |
This comment has been minimized.
This comment has been minimized.
|
I think a consistent handling would look for singleton enums rather than "univariant" (i.e. semantic rather than syntactic approach). A semantic approach would make |
This comment has been minimized.
This comment has been minimized.
vi
commented
Mar 21, 2019
Macros and code generation may write such and other redundant things. Both |
This comment has been minimized.
This comment has been minimized.
|
My issue with enumerations like
I'm not opposed to these types of |
This comment has been minimized.
This comment has been minimized.
We had that optimized for a while and it was actually a bug (rust-lang/rust#49298). |
This comment has been minimized.
This comment has been minimized.
vi
commented
Mar 29, 2019
•
|
I assumed it is indended that a singe Are partially initialized structures officialy OK per unsafe guidelines? Is this code guranteed?: #![feature(maybe_uninit,never_type,maybe_uninit_ref)]
#![allow(dead_code)]
use std::mem::MaybeUninit;
struct A { b:!, c:i32 }
fn main() {
let mut a : MaybeUninit<A> = MaybeUninit::uninitialized();
unsafe { a.get_mut().c = 5; }
println!("{}", unsafe { a.get_ref().c } );
}If yes then it makes |
rfcbot
added
finished-final-comment-period
and removed
final-comment-period
labels
Mar 30, 2019
This comment has been minimized.
This comment has been minimized.
rfcbot
commented
Mar 30, 2019
|
The final comment period, with a disposition to merge, as per the review above, is now complete. As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed. The RFC will be merged soon. |
This comment has been minimized.
This comment has been minimized.
|
Note that the second example:
works without this feature, since it only requires layout compatibility, and not |
mjbshaw commentedFeb 25, 2019
•
edited
Let's allow
#[repr(transparent)]onunions and univariantenums that have exactly one non-zero-sized field (just likestructs).Rendered.
Pre-RFC Discourse discussion on internals.rust-lang.org.