Skip to content

Make niches part of layout and expand call ABI #153

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

Closed
wants to merge 16 commits into from
49 changes: 47 additions & 2 deletions reference/src/glossary.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

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.
Expand All @@ -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),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ScalarPair is missing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's intentional. ScalarPair is an implementation detail useful for some optimizations that we don't want to guarantee it exists - right @eddyb ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it's just an aggregate that we pass around as two scalars only in Rust ABIs and within functions.

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

Expand Down