diff --git a/src/exotic-sizes.md b/src/exotic-sizes.md index d2cd82f..2a9d276 100644 --- a/src/exotic-sizes.md +++ b/src/exotic-sizes.md @@ -105,9 +105,12 @@ knowing that it's *statically impossible* for this value to be an `Err`, as this would require providing a value of type `Void`. In principle, Rust can do some interesting analyses and optimizations based -on this fact. For instance, `Result` could be represented as just `T`, -because the `Err` case doesn't actually exist. The following *could* also -compile: +on this fact. For instance, `Result` is represented as just `T`, +because the `Err` case doesn't actually exist (strictly speaking, this is only +an optimization that is not guaranteed, so for example transmuting one into the +other is still UB). + +The following *could* also compile: ```rust,ignore enum Void {} @@ -118,8 +121,7 @@ let res: Result = Ok(0); let Ok(num) = res; ``` -But neither of these tricks work today, so all Void types get you is -the ability to be confident that certain situations are statically impossible. +But this trick doesn't work yet. One final subtle detail about empty types is that raw pointers to them are actually valid to construct, but dereferencing them is Undefined Behavior diff --git a/src/other-reprs.md b/src/other-reprs.md index 139ee4c..493e047 100644 --- a/src/other-reprs.md +++ b/src/other-reprs.md @@ -1,6 +1,7 @@ # Alternative representations Rust allows you to specify alternative data layout strategies from the default. +There's also the [reference]. @@ -50,6 +51,24 @@ compiled as normal.) +# repr(transparent) + +This can only be used on structs with a single non-zero-sized field (there may +be additional zero-sized fields). The effect is that the layout and ABI of the +whole struct is guaranteed to be the same as that one field. + +The goal is to make it possible to transmute between the single field and the +struct. An example of that is the [`UnsafeCell`], which can be transmuted into +the type it wraps. + +Also, passing the struct through FFI where the inner field type is expected on +the other side is allowed. In particular, this is necessary for `struct +Foo(f32)` to have the same ABI as `f32`. + +More details are in the [RFC][rfc-transparent]. + + + # repr(u*), repr(i*) These specify the size to make a field-less enum. If the discriminant overflows @@ -88,12 +107,27 @@ compiler might be able to paper over alignment issues with shifts and masks. However if you take a reference to a packed field, it's unlikely that the compiler will be able to emit code to avoid an unaligned load. -**[As of Rust 1.0 this can cause undefined behavior.][ub loads]** +**[As of Rust 1.30.0 this still can cause undefined behavior.][ub loads]** `repr(packed)` is not to be used lightly. Unless you have extreme requirements, this should not be used. This repr is a modifier on `repr(C)` and `repr(rust)`. +# repr(align(n)) + +`repr(align(n))` (where `n` is a power of two) forces the type to have an +alignment of *at least* n. + +This enables several tricks, like making sure neighboring elements of an array +never share the same cache line with each other (which may speed up certain +kinds of concurrent code). + +This is a modifier on `repr(C)` and `repr(rust)`. It is incompatible with +`repr(packed)`. + +[reference]: https://github.com/rust-rfcs/unsafe-code-guidelines/tree/master/reference/src/representation [drop flags]: drop-flags.html [ub loads]: https://github.com/rust-lang/rust/issues/27060 +[`UnsafeCell`]: ../std/cell/struct.UnsafeCell.html +[rfc-transparent]: https://github.com/rust-lang/rfcs/blob/master/text/1758-repr-transparent.md diff --git a/src/repr-rust.md b/src/repr-rust.md index c975090..e3fd561 100644 --- a/src/repr-rust.md +++ b/src/repr-rust.md @@ -20,6 +20,7 @@ Rust gives you the following ways to lay out composite data: * tuples (anonymous product types) * arrays (homogeneous product types) * enums (named sum types -- tagged unions) +* unions (untagged) An enum is said to be *field-less* if none of its variants have associated data. @@ -38,7 +39,7 @@ struct A { will be 32-bit aligned on an architecture that aligns these primitives to their respective sizes. The whole struct will therefore have a size that is a multiple -of 32-bits. It will potentially become: +of 32-bits. It may become: ```rust struct A { @@ -50,6 +51,17 @@ struct A { } ``` +or maybe: + +```rust +struct A { + b: u32, + c: u16, + a: u8, + _pad: u8, +} +``` + There is *no indirection* for these types; all data is stored within the struct, as you would expect in C. However with the exception of arrays (which are densely packed and in-order), the layout of data is not by default specified in diff --git a/src/what-unsafe-does.md b/src/what-unsafe-does.md index 9b94136..2ebd917 100644 --- a/src/what-unsafe-does.md +++ b/src/what-unsafe-does.md @@ -6,6 +6,7 @@ The only things that are different in Unsafe Rust are that you can: * Call `unsafe` functions (including C functions, compiler intrinsics, and the raw allocator) * Implement `unsafe` traits * Mutate statics +* Access fields of `union`s That's it. The reason these operations are relegated to Unsafe is that misusing any of these things will cause the ever dreaded Undefined Behavior. Invoking