-
Notifications
You must be signed in to change notification settings - Fork 58
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
Is repr(transparent)
completely transparent within repr(Rust)
types?
#298
Comments
I've asked this question before and the answer at the time was no. It would be nice for a lot of things, enums or not. (One example of why it would be nice is that there's certainly code out there that assumes this is true already). |
I'm curious, was there any reasoning given behind that no answer? |
ah, @mystor pointed out a flaw: I forgot about niche optimizations. I wonder if there's still a way to get something here that allows for in-place initialization of Rust enums |
At the very least it can affect enum layout optimization, since |
I think just that I suspect changing this for a |
In particular, a slight variation on your example shows that it is affected by the niche optimization: enum Enum {
A,
B(Foo)
}
enum EnumUninit { // not layout compatible with Enum!
A,
B(MaybeUninit<Foo>)
} How feasible is it to just use |
n-place initialization of something like I can't really imagine how that would work. |
@RalfJung well an We'd just need a new intrinsic that's sort of the opposite of Then you do two steps:
As long as you write the correct types for the variant you want then any niches would be taken care of automatically. |
all of these do not contain a valid instance of the inner type in their bits if the value is currently None. |
I don't see a problem? I'm imagining having a
Neither of these can be structured as "regular" rust function-style intrinsics, but there's definitely something doable there. The compiler knows how that niche is exploited, and it should be possible to ask the compiler how. It's not great that currently there is no safe way to do this; if uninitialized values are going to be UB there has got to be a defined way to manipulate uninitialized enums. |
Something with a lot of intrinsics could work, but then For structs, what we do is we can take a raw ptr to |
I think
Perhaps a solution might be to have a built-in pat_offsets!(Option<String>, Some(x) => {
// in this scope, `x` is a `usize` containing the offset of a binding `x` of
// the `Some` variant of a value of type `Option<String>`
}); There'd still need to be a mechanism for setting the discriminant (possibly to be called after the value payloads are written in, I suppose, to handle niche optimizations properly), but that could probably be done with a normal intrinsic and the unsafe fn write_discriminant<T: DiscriminantKind>(to: *mut T, discr: <T as DiscriminantKind>::Discriminant); Getting this to somehow work with how we do let mut out: MaybeUninit<Option<T>> = ...;
let value: T = ...;
let offset = unsafe {
let base = <MaybeUninit<Option<T>::{Some}>>::uninit();
addr_of!((*base.as_ptr()).0).offset_from(base.as_ptr()) as usize
};
unsafe {
ptr::write(out.as_mut_ptr().add(offset) as *mut T, value);
write_discriminant(out.as_mut_ptr(), <Option<T>::{Some}>::DISCRIMINANT);
} |
In that case I think it'd be better to close this issue and open a new one focused on the problem. This issue contains a bunch of irrelevant discussion. I'm not even sure if this is a UCG thing, since we will need language extensions for this -- UCG is mostly about "how do I best sue the unsafe part of the language", this is about "how can we extend the language to support this use-case that we currently do not support". |
Yeah, I opened this here because I thought clarifying |
Yes, that would indeed have been a UCG thing. :) |
I have tried to document everything I believe we have consensus on. I've left some things open that I possibly could have closed, but because this PR is very big, I would like to focus on getting it in as quickly as possible and worrying about whatever's left aftwards. I strongly encourage others to submit follow up PRs to close out the other open issues. Closes rust-lang#156. Closes rust-lang#298. Closes rust-lang#352.
I have tried to document everything I believe we have consensus on. I've left some things open that I possibly could have closed, but because this PR is very big, I would like to focus on getting it in as quickly as possible and worrying about whatever's left aftwards. I strongly encourage others to submit follow up PRs to close out the other open issues. Closes rust-lang#156. Closes rust-lang#298. Closes rust-lang#352.
repr(transparent)
exists which makes it safe to cast references between e.g.MaybeUninit<T>
andT
Does this extend to
repr(Rust)
types containingrepr(transparent)
? I.e., are we guaranteed that the following pairs of types:are fully layout compatible? The primary guarantee of
repr(transparent)
is that it does not affect the size and alignment, but my understanding is that at the momentrepr(Rust)
has no guarantees; it would be legal forrepr(Rust)
to say "add a padding of 2 in every field whose type starts with an 'M'".This guarantee would be very nice to have; because otherwise there's no way to do in-place initialization of Rust enums without
repr(C)
.cc @rust-lang/lang (unsure if this is the right place to file this)
The text was updated successfully, but these errors were encountered: