-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Transparent Unions and Enums #2645
Conversation
Co-Authored-By: mjbshaw <github@mjb.io>
Co-Authored-By: mjbshaw <github@mjb.io>
Co-Authored-By: mjbshaw <github@mjb.io>
Co-Authored-By: mjbshaw <github@mjb.io>
Co-Authored-By: mjbshaw <github@mjb.io>
Co-Authored-By: mjbshaw <github@mjb.io>
Co-Authored-By: mjbshaw <github@mjb.io>
Co-Authored-By: mjbshaw <github@mjb.io>
Co-Authored-By: mjbshaw <github@mjb.io>
Co-Authored-By: mjbshaw <github@mjb.io>
Co-Authored-By: mjbshaw <github@mjb.io>
Co-Authored-By: mjbshaw <github@mjb.io>
Co-Authored-By: mjbshaw <github@mjb.io>
Co-Authored-By: mjbshaw <github@mjb.io>
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. |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
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. |
@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 |
@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. |
@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. |
Shall this be allowed?: #[repr(transparent)]
enum StaringIntoTheVoid {
Empty(!),
Lifeline(i32),
DoublyNothing(!,!),
} What is interaction between |
@vi Interesting, I hadn't thought of that case. Currently the plan is to allow only single-variant |
Obviously, the same as |
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 |
Macros and code generation may write such and other redundant things. Both |
My issue with enumerations like
I'm not opposed to these types of |
We had that optimized for a while and it was actually a bug (rust-lang/rust#49298). |
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 |
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. |
Note that the second example:
works without this feature, since it only requires layout compatibility, and not |
I have a dumb question, is #[repr(transparent)] union<T> U { t: T, u: () } ok? What happens if I write |
FWIW with structs that is allowed, and |
Huzzah! This RFC has been merged! Tracking issue: rust-lang/rust#60405 (Please excuse the delay!) |
Looks like there might be a use-case after all for by-value |
…enkov Stabilize `#[repr(transparent)]` on `enum`s in Rust 1.42.0 # Stabilization report The following is the stabilization report for `#![feature(transparent_enums)]`. Tracking issue: #60405 [Version target](https://forge.rust-lang.org/#current-release-versions): 1.42 (2020-01-30 => beta, 2020-03-12 => stable). ## User guide A `struct` with only a single non-ZST field (let's call it `foo`) can be marked as `#[repr(transparent)]`. Such a `struct` has the same layout and ABI as `foo`. Here, we also extend this ability to `enum`s with only one variant, subject to the same restrictions as for the equivalent `struct`. That is, you can now write: ```rust #[repr(transparent)] enum Foo { Bar(u8) } ``` which, in terms of layout and ABI, is equivalent to: ```rust #[repr(transparent)] struct Foo(u8); ``` ## Motivation This is not a major feature that will unlock new and important use-cases. The utility of `repr(transparent)` `enum`s is indeed limited. However, there is still some value in it: 1. It provides conceptual simplification of the language in terms of treating univariant `enum`s and `struct`s the same, as both are product types. Indeed, languages like Haskell only have `data` as the only way to construct user-defined ADTs in the language. 2. In rare occasions, it might be that the user started out with a univariant `enum` for whatever reason (e.g. they thought they might extend it later). Now they want to make this `enum` `transparent` without breaking users by turning it into a `struct`. By lifting the restriction here, now they can. ## Technical specification The reference specifies [`repr(transparent)` on a `struct`](https://doc.rust-lang.org/nightly/reference/type-layout.html#the-transparent-representation) as: > ### The transparent Representation > > The `transparent` representation can only be used on `struct`s that have: > - a single field with non-zero size, and > - any number of fields with size 0 and alignment 1 (e.g. `PhantomData<T>`). > > Structs with this representation have the same layout and ABI as the single non-zero sized field. > > This is different than the `C` representation because a struct with the `C` representation will always have the ABI of a `C` `struct` while, for example, a struct with the `transparent` representation with a primitive field will have the ABI of the primitive field. > > Because this representation delegates type layout to another type, it cannot be used with any other representation. Here, we amend this to include univariant `enum`s as well with the same static restrictions and the same effects on dynamic semantics. ## Tests All the relevant tests are adjusted in the PR diff but are recounted here: - `src/test/ui/repr/repr-transparent.rs` checks that `repr(transparent)` on an `enum` must be univariant, rather than having zero or more than one variant. Restrictions on the fields inside the only variants, like for those on `struct`s, are also checked here. - A number of codegen tests are provided as well: - `src/test/codegen/repr-transparent.rs` (the canonical test) - `src/test/codegen/repr-transparent-aggregates-1.rs` - `src/test/codegen/repr-transparent-aggregates-2.rs` - `src/test/codegen/repr-transparent-aggregates-3.rs` - `src/test/ui/lint/lint-ctypes-enum.rs` tests the interactions with the `improper_ctypes` lint. ## History - 2019-04-30, RFC rust-lang/rfcs#2645 Author: @mjbshaw Reviewers: The Language Team This is the RFC that proposes allowing `#[repr(transparent)]` on `enum`s and `union`. - 2019-06-11, PR #60463 Author: @mjbshaw Reviewers: @varkor and @rkruppe The PR implements the RFC aforementioned in full. - 2019, PR #67323 Author: @Centril Reviewers: @davidtwco The PR reorganizes the static checks taking advantage of the fact that `struct`s and `union`s are internally represented as ADTs with a single variant. - This PR stabilizes `transparent_enums`. ## Related / possible future work The remaining work here is to figure out the semantics of `#[repr(transparent)]` on `union`s and stabilize those. This work continues to be tracked in #60405.
Let's allow
#[repr(transparent)]
onunion
s and univariantenum
s that have exactly one non-zero-sized field (just likestruct
s).Rendered.
Tracking issue: rust-lang/rust#60405
Pre-RFC Discourse discussion on internals.rust-lang.org.