-
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
Add a pod
language item and marker trait.
#1387
Conversation
Forgot that rust doesn't have function pointers, only function references. Edit: Since those references are not allowed to be |
I've looked a bit into how LLVM treats padding:
In order to avoid reading Note that this only affects Pod structs and tuples where padding should be rare anyway. For example, in the following struct the compiler would insert the padding field: #[derive(Pod)]
struct X {
a: u8,
__padding: [u8; 7], // or 3 depending on the alignment of u64
b: u64
} Once C unions are added, something similar will have to be done for them. |
All |
@oli-obk |
Uhm right. That's not better. |
The lack of function pointers is a safety problem anyway. This RFC will not try to solve it. |
Actually this is because extern fn in an extern block implicitly adds an unsafe to it. The actual type of such a function is really unsafe extern fn which is always unsafe to call. |
In general I like this RFC. Solving the padding problem by adding never used fields, seems like a reasonable workaround (that said - I haven't actually looked into LLVM, so not sure). |
cannot modify the `len` field in order to guarantee safety. Since the compiler | ||
cannot know if the private fields must satisfy certain invariants, an | ||
implementation of the safe (!) `Pod` trait cannot be allowed for such types. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't agree with the reasoning w r t allowing safe Pod
for types with private internals. If a struct is declared Pod
, then it's an error to assume that there are private invariants. (A struct might want to keep its internals private for other reasons, such as being able to rename the fields without breaking the API.)
I disagree with the idea that all fields have to be public. Why would you have that restriction? Just make it a trait like Copy, all inside types have to be Pod in order for the outside type to be Pod. |
I feel like this would be quite useful for my embedded project. I feel like I would otherwise be using the byteorder crate. Speaking of byteorder, could you amend this to clarify what happens when you cast a struct with 4 u8s into a struct with only a u32. |
@tbelaire Well, it's implementation defined. On x86, it'll be little endian, and on ARM, it'll be big endian. The point is it's not memory unsafe. Also, this makes me think of a second thing. Currently, we do not specify our struct layout. This would force us to make our struct layout equal to repr(C). I would argue that we should only be able to make repr(C) types PoD. Unless, perhaps, you have a different idea @mahkoh? |
Changes in the last update:
Regarding padding: The behavior specified in the RFC is sufficient unless undef values have been explicitly stored in a @tbelaire: Whatever currently happens. @GBGamer: How does it imply C layout? |
I've experimented with pod types and generally found it to be something better suited for an external library than stdlib. However, integrating it cleanly requires (the stabilization of) either OIBITs or syntax extensions. The proposed feature of getting around LLVM's undef'd member padding is interesting though, since syntax extensions can't do that. My solution has been to simply require the structure to be packed to an alignment of 1. |
@arcnmx Note that if you do force it to be packed using |
@arcnmx: I don't see how it can work with either since 1. enums must not be
Then it is good that this RFC does not propose any changes to the stdlib. It provides the necessary building blocks to safely implement |
This seems closely related to ye olde |
Yeah, I wrote it all before that RFC existed. I also have a marker trait (could be OIBIT, isn't currently because they're unstable) specifying that all members are 1-aligned, which also works.
It does, though. Derive syntax extensions can make assertions that all member types satisfy a given trait constraint (i.e. is POD), and they can also refuse to apply to enum types. This is what my library does, and can be used on stable with syntex, etc.
Sorry, misspoke. I meant "language" as I see little point for it to be a language item. The new things this brings to the table are:
|
@mahkoh It's currently undefined behavior to transmute non-repr(C). Therefore, it's UB to, say, do this: struct Test {
inner: u8
}
let array: &[u8] = [0u8; 128];
let slice = std::slice::from_raw_parts(array.as_ptr(), array.len()); for example. Also, it should be something like Copy, imo: #[repr(C)]
#[derive(Copy, Clone, Pod)]
pub struct ControllerAxis {
pub start: Point<f32>,
pub min: Point<f32>,
pub max: Point<f32>,
pub end: Point<f32>,
} for an example from a game I'm currently working on. |
That's a clever trick and much more flexible than this RFC. I've implemented this in my code and it's working nicely apart from the usual array problems. The
The concept of undefined behavior does not apply to rust. So little of the language is actually defined that, if it were to apply to rust, you'd find that if you're using the standard library, the behavior is undefined. For example, the manual does not define the behavior upon a |
Closing because this can be solved with compiler plugins apart from the padding issue. |
Add a
pod
language item and marker trait. The trait can only be implemented bya subset of all types and identifies objects that are valid when they contain
arbitrary bit patterns.