diff --git a/reference/src/glossary.md b/reference/src/glossary.md index 3b9cf4f7..6a0bdde4 100644 --- a/reference/src/glossary.md +++ b/reference/src/glossary.md @@ -53,8 +53,16 @@ For some more information, see [this blog post](https://www.ralfj.de/blog/2018/0 #### Layout -The *layout* of a type defines its size and alignment as well as the offsets of its subobjects (e.g. fields of structs/unions/enum/... or elements of arrays). -Moreover, the layout of a type records its *function call ABI* (or just *ABI* for short): how the type is passed *by value* across a function boundary. +The *layout* of a type defines: + +* its size, +* its alignment, +* its field offsets (e.g. fields of structs, union, enums, arrays, ...) +* its [niches](#niche), +* its [call abi](#call-abi). + +Note: due to discriminant-elision optimizations, niches are required to compute +the layout of, e.g., `Option<T>`, from the layout of `T`. Note: Originally, *layout* and *representation* were treated as synonyms, and Rust language features like the `#[repr]` attribute reflect this. In this document, *layout* and *representation* are not synonyms. @@ -73,6 +81,43 @@ niches. For example, the "all bits uninitialized" is an invalid bit-pattern for `&mut T`, but this bit-pattern cannot be used by layout optimizations, and is not a niche. +#### Call ABI + +The *call ABI* determines how a type is passed *by value* across a function boundary. + +Note: The set of possible call ABIs is not stable. Currently, it consists of: + +```rust,ignore +enum Abi { + Uninhabited, + Scalar(Scalar), + Vector { + element: Scalar, + count: u64 + }, + Aggregate { + // If true, the layout size of the aggregate is exact. + // Otherwise, the layout size of the aggregate is + // a lower bound. + sized: bool, + } +} +``` + +where a `Scalar` is either a primitive integer, floating point, or a pointer to +a sized type. + +For example, the call ABI of: + +* `i32` is `Scalar(I32)`, +* `#[repr(C)] struct Wrapper(i32);` is `Aggregate { sized: true }`. +* `#[repr(transparent)] struct Wrapper(i32);` is `Scalar(I32)`. + +The call ABI of `repr(Rust)` types is unspecified. The following is not +guaranteed, but right now the call ABI of: + +* `/*#[repr(Rust)]*/ struct Wrapper(i32);` (without `repr(transparent)`) is also + `Scalar(I32)` - only larger `struct`s are aggregates. ### TODO diff --git a/reference/src/layout/arrays-and-slices.md b/reference/src/layout/arrays-and-slices.md index 375d1571..bf356fc5 100644 --- a/reference/src/layout/arrays-and-slices.md +++ b/reference/src/layout/arrays-and-slices.md @@ -10,8 +10,9 @@ The _offset_ of the first array element is `0`, that is, a pointer to the array and a pointer to its first element both point to the same memory address. The _alignment_ of array types is greater or equal to the alignment of its -element type. If the element type is `repr(C)` the layout of the array is -guaranteed to be the same as the layout of a C array with the same element type. +element type. If the element type is `repr(C)` the size and alignment of the +array is guaranteed to be the same as the size and alignment of a C array with +the same element type. > **Note**: the type of array arguments in C function signatures, e.g., `void > foo(T x[N])`, decays to a pointer. That is, these functions do not take arrays diff --git a/reference/src/layout/function-pointers.md b/reference/src/layout/function-pointers.md index 3188fb05..e9fe4782 100644 --- a/reference/src/layout/function-pointers.md +++ b/reference/src/layout/function-pointers.md @@ -25,7 +25,7 @@ or the address of a function. ### Representation -The ABI and layout of `(unsafe)? (extern "ABI")? fn(Args...) -> Ret` +The size, alignment, and call ABI of `(unsafe)? (extern "ABI")? fn(Args...) -> Ret` is exactly that of the corresponding C type -- the lack of a null value does not change this. On common platforms, this means that `*const ()` and `fn(Args...) -> Ret` have diff --git a/reference/src/layout/pointers.md b/reference/src/layout/pointers.md index 336651ef..9d965578 100644 --- a/reference/src/layout/pointers.md +++ b/reference/src/layout/pointers.md @@ -28,15 +28,18 @@ and are at least one word. ### Notes -The layouts of `&T`, `&mut T`, `*const T` and `*mut T` are the same. +The size, alignment, and call ABI of `&T`, `&mut T`, `*const T` and `*mut T` are +the same. -If `T` is sized, references and pointers to `T` have a size and alignment of one -word and have therefore the same layout as C pointers. +If `T` is sized, the size, alignment, and call ABI of references and pointers to +`T` is the same as that of C pointers. -> **warning**: while the layout of references and pointers is compatible with -> the layout of C pointers, references come with a _validity_ invariant that -> does not allow them to be used when they could be `NULL`, unaligned, dangling, -> or, in the case of `&mut T`, aliasing. +> **warning**: while the size, alignment, and call ABI of references and +> pointers is compatible with the layout of C pointers, references come with a +> _validity_ invariant that does not allow them to be used when they could be +> `NULL`, unaligned, dangling, or, in the case of `&mut T`, aliasing. Since the +> niches of references and pointers are not the same, these types are not +> layout-compatible with each other. We do not make any guarantees about the layout of multi-trait objects `&(dyn Trait1 + Trait2)` or references to other dynamically sized types, @@ -53,7 +56,7 @@ struct DynObject { > **note**: In the layout of `&dyn mut Trait` the field `data` is of the type `*mut u8`. -The layout of `&[T]` is the same as that of: +The size, alignment, and call ABI of `&[T]` and `&mut [T]` are the same as that of: ```rust #[repr(C)] struct Slice<T> { @@ -62,7 +65,11 @@ struct Slice<T> { } ``` -> **note**: In the layout of `&mut [T]` the field `ptr` is of the type `*mut T`. +> **note**: the field `ptr` is of the type `*mut T` for `&mut [T]`. -The layout of `&str` is the same as that of `&[u8]`, and the layout of `&mut str` is -the same as that of `&mut [u8]`. +The size, alignment, and call ABI of `&str` is the same as that of `&[u8]`, and +the layout of `&mut str` is the same as that of `&mut [u8]`. + +#### Unresolved question + +* Does `&str` have the same niches as `&[u8]` ? diff --git a/reference/src/layout/scalars.md b/reference/src/layout/scalars.md index 7b647cbc..8170dfa9 100644 --- a/reference/src/layout/scalars.md +++ b/reference/src/layout/scalars.md @@ -10,9 +10,9 @@ layout `#[repr()]` flags. ## `bool` -Rust's `bool` has the same layout as C17's` _Bool`, that is, its size and -alignment are implementation-defined. Any `bool` can be cast into an integer, -taking on the values 1 (`true`) or 0 (`false`). +Rust's `bool` has the same layout as C17's` _Bool` which is +implementation-defined. Any `bool` can be cast into an integer, taking on the +values 1 (`true`) or 0 (`false`). > **Note**: on all platforms that Rust's currently supports, its size and > alignment are 1, and its ABI class is `INTEGER` - see [Rust Layout and ABIs].