-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
Improve shallow Clone
deriving
#36384
Conversation
Extended with the same improvements to |
Hmm, why is it sometimes |
@durka In the first case we already know that In the second case we don't know if |
Why not On Sun, Sep 11, 2016 at 11:06 AM, Vadim Petrochenkov <
|
I'm surprised this works actually. I expected impls with always-false predicates to be ignored without errors (i.e. |
Awesome wins @petrochenkov! Seems like a great idea to me and is a great way to cut down on the amount of code generated as well. I've only been personally following unions at a distance, though, and don't feel qualified enough to say whether or not it should be allowed to have these |
I think I prefer the current implementation after all.
compiles with "where Copy" implementation of derive, but despite that for any |
So, syntactically, unions should allow having an attached |
Nah,
|
@petrochenkov Ah, I didn't realize that about Eq; in that case, deriving Eq (but not PartialEq) seems fine. Deriving Copy seems plausible but potentially problematic. Suppose I have a UB aside, copying padding shouldn't do any harm. so if the Copy implementation doesn't invoke UB, deriving it for unions containing entirely Copy fields seems OK. |
@joshtriplett |
@petrochenkov Logically, |
CCing @ubsan for review here. |
Padding isn't UB, it merely has the value undef which is okay to memcpy (which results in the destination padding also being undef). It's only if you try to actually do anything based on the value of the padding that UB steps in and ruins your day. So implementing |
@retep998 Thanks! That makes sense. Based on that, I agree that |
@petrochenkov is a particular reason to allow For |
No, I just went through all derivable traits and supported everything that can be supported. |
Perhaps it could be left out just to be conservative? I can see how |
@retep998 That's only the logic for LLVM, not for Rust. It's not okay in Rust to read/write undef, but I'd argue it should be, at least for bytes. |
I don't think there are any reasons to be conservative in this particular case. |
An example of equality comparable union:
|
@petrochenkov yeah I'm certainly not disagreeing that it's possible, nor that it's desired in some use cases. I just tend to far prefer conservative approaches. We can always add the feature but we can basically never take it out. For me the surprise factor is so high ( |
This reminds me the joke about docking a dog's tail slice by slice, so the poor dog doesn't lose it all at once. I know, the |
It seems like the concrete motivation for this PR was improving Due to the limited utility today, the fact that it was just tacked onto this PR, and that it's easy to enable at any time (perhaps in a more principled fashion with other |
The motivation was to finish my work on unions that was blocked by |
FWIW, we can take it out - unions are unstable (but I can't imagine why would we do that). |
Improve shallow `Clone` deriving `Copy` unions now support `#[derive(Clone)]`. Less code is generated for `#[derive(Clone, Copy)]`. + Unions now support `#[derive(Eq)]`. Less code is generated for `#[derive(Eq)]`. --- Example of code reduction: ``` enum E { A { a: u8, b: u16 }, B { c: [u8; 100] }, } ``` Before: ``` fn clone(&self) -> E { match (&*self,) { (&E::A { a: ref __self_0, b: ref __self_1 },) => { ::std::clone::assert_receiver_is_clone(&(*__self_0)); ::std::clone::assert_receiver_is_clone(&(*__self_1)); *self } (&E::B { c: ref __self_0 },) => { ::std::clone::assert_receiver_is_clone(&(*__self_0)); *self } } } ``` After: ``` fn clone(&self) -> E { { let _: ::std::clone::AssertParamIsClone<u8>; let _: ::std::clone::AssertParamIsClone<u16>; let _: ::std::clone::AssertParamIsClone<[u8; 100]>; *self } } ``` All the matches are removed, bound assertions are more lightweight. `let _: Checker<CheckMe>;`, unlike `checker(&check_me);`, doesn't have to be translated by rustc_trans and then inlined by LLVM, it doesn't even exist in MIR, this means faster compilation. --- Union impls are generated like this: ``` union U { a: u8, b: u16, c: [u8; 100], } ``` ``` fn clone(&self) -> U { { let _: ::std::clone::AssertParamIsCopy<Self>; *self } } ``` Fixes rust-lang#36043 cc @durka r? @alexcrichton
Copy
unions now support#[derive(Clone)]
.Less code is generated for
#[derive(Clone, Copy)]
.+
Unions now support
#[derive(Eq)]
.Less code is generated for
#[derive(Eq)]
.Example of code reduction:
Before:
After:
All the matches are removed, bound assertions are more lightweight.
let _: Checker<CheckMe>;
, unlikechecker(&check_me);
, doesn't have to be translated by rustc_trans and then inlined by LLVM, it doesn't even exist in MIR, this means faster compilation.Union impls are generated like this:
Fixes #36043
cc @durka
r? @alexcrichton