Skip to content
Merged
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
3 changes: 2 additions & 1 deletion src/behavior-considered-undefined.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ 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.

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`.

Expand Down Expand Up @@ -204,6 +204,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
7 changes: 7 additions & 0 deletions src/dynamically-sized-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

@RalfJung RalfJung Jun 25, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This definition contains redundant information with the definition of "metadata" from #2286. That doesn't seem great, we should define these things only in one place and then reference them elsewhere.

View changes since the review

@traviscross traviscross Jun 25, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Agreed. I had the same thought. I didn't have any immediate good ideas for how to resolve it, though (other than ensuring they were cross-linked, as I did). Suggestions welcome.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We could define "unsized tail" without repeating the metadata definition. For instance:

The unsized tail of an unsized type is the unsized type at the "end" of the type, after recursing through compound types:

  • A [slice] ([T]), a [str], and a [trait object] (dyn Trait) are each their own unsized tail.
  • 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.

And then for metadata I'd say something like:
[Pointer types] to DSTs are sized but have twice the size of pointers to sized types, since they also store metadata.
The metadata carries by a pointer is determined by the [unsized tail] of its pointee type:

  • If the unsized tail is a slice or str, ...
  • If the unsized tail is a trait object, ...


[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
Loading