Skip to content
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

Can the layouts of Vec<i32> and Vec<u32> guaranteed to be the same? #560

Closed
davidzeng0 opened this issue Mar 21, 2025 · 5 comments
Closed

Comments

@davidzeng0
Copy link

davidzeng0 commented Mar 21, 2025

Currently, the layouts of Vec<A> and Vec<B> have no guarantees. It would be useful in some cases to know the layout of Vec<A> for some A is the same as Vec<B>. For my usecase the exact field order doesn't matter, just that they could be the same as another type from within the same compilation.

Specifically, for any two types T and U, if their layout and alignment are the exact same, all bit patterns are valid for both, and are Freeze and Unpin, can &mut Vec<T> be transmuted to &mut Vec<U> and pushed to without immediate UB?

If such layout guarantees of Vec do not exist, can we expect them to exist at a later date?

Example

let mut v = vec![1i32];

let r: &mut Vec<u32> = unsafe { transmute(&mut v) };

r.push(2);

println!("{:?}", v);

I would also like to ask the question for Option, but Vec seems like it could achieve such a guarantee more easily because its data is behind a pointer.

@davidzeng0 davidzeng0 changed the title Are the layouts of Vec<i32> and Vec<u32> guaranteed to be the same? Can the layouts of Vec<i32> and Vec<u32> guaranteed to be the same? Mar 21, 2025
@Lokathor
Copy link
Contributor

In current rust this is not the case, but it definitely should be added eventually. It's an extremely handy property.

@CAD97
Copy link

CAD97 commented Mar 21, 2025

I believe it's currently the case that -Zrandomize-layout can result in Vec<i32> and Vec<u32> having different field orders, or if that isn't the case, that it's intended for that to be the case at some point.

One could imagine that LTO could determine some field is accessed a lot more than others and should be laid out first, and that it could make a different determination for different generic instantiations.

This isn't to say that we shouldn't provide this guarantee, just that there are real reasons why it really shouldn't be assumed.

@davidzeng0
Copy link
Author

That is certainly an intersting use case, I had not considered that LTO and/or PGO could influence field ordering.

@RalfJung
Copy link
Member

The intended way to convert Vec to its constituent parts is into_raw_parts, or the 3 methods that return the 3 parts separately. See rust-lang/rust#65816. So no, a transmute is not allowed and layouts are not stable.

I'll close the issue since the question has not been answered and as a feature request, this should be directed at t-libs-api.

@davidzeng0
Copy link
Author

I have a rather interesting use case in which I have to expose the Vec to the user and modify it in place with type erased code, so unfortunately I can't use those methods. It looks like I'll have to keep the extra variants for Vec<i32> and Vec<u32>, unless I decide to create a newtype.

Thank you everyone for your comments and insights.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants