Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions src/behavior-considered-undefined.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ r[undefined.dangling.zero-size]
If the [size is 0][zero-sized], then the pointer is trivially never "dangling" (even if it is a null pointer).

r[undefined.dangling.dynamic-size]
Note that dynamically sized types (such as slices and strings) point to their entire range, so it is important that the length metadata is never too large.
Note that dynamically sized types (such as slices and strings) point to their entire range, so it is important that the length [metadata] is never too large.

r[undefined.dangling.alloc-limit]
In particular, the dynamic size of a Rust value (as determined by `size_of_val`) must never exceed `isize::MAX`, since it is impossible for a single allocation to be larger than `isize::MAX`.
Expand Down Expand Up @@ -142,12 +142,17 @@ r[undefined.validity.union]
* For a `union`, the exact validity requirements are not decided yet. Obviously, all values that can be created entirely in safe code are valid. If the union has a [zero-sized] field, then every possible value is valid. Further details are [still being debated](https://github.com/rust-lang/unsafe-code-guidelines/issues/438).

r[undefined.validity.reference-box]
* A reference or [`Box<T>`] must be aligned and non-null, it cannot be [dangling], and it must point to a valid value (in case of dynamically sized types, using the actual dynamic type of the pointee as determined by the metadata). Note that the last point (about pointing to a valid value) remains a subject of some debate.
* A reference or [`Box<T>`] must be aligned and non-null, it cannot be [dangling], and it must point to a valid value (in case of dynamically sized types, using the actual dynamic type of the pointee as determined by the [metadata]). Note that the last point (about pointing to a valid value) remains a subject of some debate.

r[undefined.validity.wide]
* The metadata of a wide reference, [`Box<T>`], or raw pointer must match the type of the unsized tail:
* The [metadata] of a wide reference, [`Box<T>`], or raw pointer must match the type of the [unsized tail]:
* `dyn Trait` metadata must be a pointer to a compiler-generated vtable for `Trait`. (For raw pointers, this requirement remains a subject of some debate.)
* Slice (`[T]`) metadata must be a valid `usize`. Furthermore, for wide references and [`Box<T>`], slice metadata is invalid if it makes the total size of the pointed-to value bigger than `isize::MAX`.
* Slice (`[T]`) and `str` metadata must be a valid `usize`.

In addition, for a wide reference or [`Box<T>`], the metadata is invalid if it makes the total size of the pointed-to value (as determined by `size_of_val`) bigger than `isize::MAX`.

> [!NOTE]
> This bound is on the size of the entire pointed-to value, not just its unsized tail, and it constrains `dyn Trait` metadata just as it does a slice or `str` length. A valid vtable describes an erased type no larger than `isize::MAX`, but a sized prefix can still carry the total past the limit.

r[undefined.validity.valid-range]
* If a type has a custom range of a valid values, then a valid value must be in that range. In the standard library, this affects [`NonNull<T>`] and [`NonZero<T>`].
Expand All @@ -156,7 +161,7 @@ r[undefined.validity.valid-range]
> `rustc` achieves this with the unstable `rustc_layout_scalar_valid_range_*` attributes.

r[undefined.validity.const-provenance]
* **In [const contexts]**: In addition to what is described above, further provenance-related requirements apply during const evaluation. Any value that holds pure integer data (the `i*`/`u*`/`f*` types as well as `bool` and `char`, enum discriminants, and slice metadata) must not carry any provenance. Any value that holds pointer data (references, raw pointers, function pointers, and `dyn Trait` metadata) must either carry no provenance, or all bytes must be fragments of the same original pointer value in the correct order.
* **In [const contexts]**: In addition to what is described above, further provenance-related requirements apply during const evaluation. Any value that holds pure integer data (the `i*`/`u*`/`f*` types as well as `bool` and `char`, enum discriminants, and slice [metadata]) must not carry any provenance. Any value that holds pointer data (references, raw pointers, function pointers, and `dyn Trait` metadata) must either carry no provenance, or all bytes must be fragments of the same original pointer value in the correct order.

This implies that transmuting or otherwise reinterpreting a pointer (reference, raw pointer, or function pointer) into a non-pointer type (such as integers) is undefined behavior if the pointer had provenance.

Expand Down Expand Up @@ -194,6 +199,7 @@ r[undefined.validity.undef]
[`target_feature`]: attributes/codegen.md#the-target_feature-attribute
[`UnsafeCell<U>`]: std::cell::UnsafeCell
[Rustonomicon]: ../nomicon/index.html
[metadata]: dynamic-sized.pointer-types
[`NonNull<T>`]: core::ptr::NonNull
[`NonZero<T>`]: core::num::NonZero
[place expression context]: expressions.md#place-expressions-and-value-expressions
Expand All @@ -203,6 +209,7 @@ r[undefined.validity.undef]
[project-field]: expressions/field-expr.md
[project-tuple]: expressions/tuple-expr.md#tuple-indexing-expressions
[project-slice]: expressions/array-expr.md#array-and-slice-indexing-expressions
[unsized tail]: dynamic-sized.tail
[unwinding-ffi]: panic.md#unwinding-across-ffi-boundaries
[const-promoted]: destructors.md#constant-promotion
[lifetime-extended]: destructors.md#temporary-lifetime-extension
Expand Down
13 changes: 10 additions & 3 deletions src/dynamically-sized-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ r[dynamic-sized.restriction]
Such types can only be used in certain cases:

r[dynamic-sized.pointer-types]
* [Pointer types] to <abbr title="dynamically sized types">DSTs</abbr> are sized but have twice the size of pointers to sized types
* Pointers to slices and `str` also store the number of elements.
* Pointers to trait objects also store a pointer to a vtable.
* [Pointer types] to <abbr title="dynamically sized types">DSTs</abbr> are sized but have twice the size of pointers to sized types, since they also store *metadata*:
* Pointers to slices store the number of elements; pointers to `str` store the length in bytes.
* Pointers to trait objects store a pointer to a vtable.

r[dynamic-sized.question-sized]
* <abbr title="dynamically sized types">DSTs</abbr> can be provided as type arguments to generic type parameters having the special `?Sized` bound. They can also be used for associated type definitions when the corresponding associated type declaration has a `?Sized` bound. By default, any type parameter or associated type has a `Sized` bound, unless it is relaxed using `?Sized`.
Expand All @@ -25,10 +25,17 @@ r[dynamic-sized.struct-field]
> [!NOTE]
> [Variables], function parameters, [const] items, and [static] items must be `Sized`.

r[dynamic-sized.tail]
The *unsized tail* of a type is the dynamically sized component that the [metadata] of a pointer to the type describes. A [slice] (`[T]`) and a [`str`] are each their own unsized tail, described by a length; a [trait object] (`dyn Trait`) is its own unsized tail, described by a pointer to a vtable. When a struct (per [dynamic-sized.struct-field]) or a tuple has an unsized last field, its unsized tail is the unsized tail of that field. A sized type has no unsized tail.

[metadata]: dynamic-sized.pointer-types
[sized]: special-types-and-traits.md#sized
[Slices]: types/slice.md
[slice]: types/slice.md
[str]: types/str.md
[`str`]: types/str.md
[trait objects]: types/trait-object.md
[trait object]: types/trait-object.md
[Pointer types]: types/pointer.md
[Variables]: variables.md
[const]: items/constant-items.md
Expand Down
3 changes: 2 additions & 1 deletion src/expressions/operator-expr.md
Original file line number Diff line number Diff line change
Expand Up @@ -732,7 +732,7 @@ r[expr.as.pointer.sized]
> ```

r[expr.as.pointer.discard-metadata]
- If `T` is unsized and `U` is sized, the cast discards all metadata that completes the wide pointer `T` and produces a thin pointer `U` consisting of the data part of the unsized pointer.
- If `T` is unsized and `U` is sized, the cast discards all [metadata] that completes the wide pointer `T` and produces a thin pointer `U` consisting of the data part of the unsized pointer.

> [!EXAMPLE]
> ```rust
Expand Down Expand Up @@ -1244,6 +1244,7 @@ As with normal assignment expressions, compound assignment expressions always pr
[logical not]: ../types/boolean.md#logical-not
[logical or]: ../types/boolean.md#logical-or
[logical xor]: ../types/boolean.md#logical-xor
[metadata]: dynamic-sized.pointer-types
[moved from]: expr.move.movable-place
[mutable]: ../expressions.md#mutability
[place expression]: ../expressions.md#place-expressions-and-value-expressions
Expand Down
Loading