Skip to content

Commit 3c21957

Browse files
committed
Document transmutability of pointer types
Our rules for `as` casts document which pointer-to-pointer casts are valid. For unsized types, this validity is based on the compatibility of the pointer metadata. Using this and our layout equivalences, we can define when a pointer transmute will produce the same pointer value as would a cast. Let's define that.
1 parent 7a900bc commit 3c21957

1 file changed

Lines changed: 22 additions & 0 deletions

File tree

src/types/pointer.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,23 @@ r[type.pointer.smart]
6363

6464
The standard library contains additional 'smart pointer' types beyond references and raw pointers.
6565

66+
r[type.pointer.transmute]
67+
## Transmutation
68+
69+
r[type.pointer.transmute.cast]
70+
When `*const T` and `*const U` have the same layout (per [layout.pointer.parametric]), transmuting a `*const T` to a `*const U` reinterprets the pointer value --- its address and [metadata] --- unchanged. When `T` and `U` are both sized or both have a slice or `str` as their [unsized tail], this produces the same value as a [pointer-to-pointer cast] from `*const T` to `*const U` (where such a cast is permitted), since the cast copies the metadata unchanged. The same holds between `*mut T` and `*mut U`. Transmuting between the reference types `&T` and `&U`, or between `&mut T` and `&mut U`, reinterprets the pointer value the same way, but is sound only when the result is aligned for the target type and points to a valid value of it, as required by [undefined.validity.reference-box] and [undefined.validity.wide].
71+
72+
```rust
73+
let ptr: *const i8 = &1;
74+
let cast = ptr as *const u8;
75+
// Transmuting this pointer is equivalent to casting it with `as`.
76+
let transmuted = unsafe { *(&raw const ptr as *const *const u8) };
77+
assert_eq!(cast, transmuted);
78+
```
79+
80+
> [!NOTE]
81+
> This equivalence with the cast does not extend to trait objects. The conversions permitted for `as` casts between trait-object pointers --- adding or removing an auto trait, and a [trait object upcast] (converting `*const dyn Sub` to `*const dyn Super` when `Super` is a supertrait of `Sub`) --- are [unsized coercions][unsized coercion], not pointer-to-pointer casts. The conversion builds a vtable for the target type, whereas a transmute keeps the source vtable. For an auto-trait change the kept vtable is still valid, so the transmute is sound but does not necessarily produce the same pointer value as the cast. For an upcast, the kept vtable is `Sub`'s, which is not valid for `Super`, so the transmuted pointer is invalid.
82+
6683
r[type.pointer.validity]
6784
## Bit validity
6885

@@ -75,5 +92,10 @@ For thin raw pointers (i.e., for `P = *const T` or `P = *mut T` for `T: Sized`),
7592
[Interior mutability]: ../interior-mutability.md
7693
[`unsafe` operation]: ../unsafety.md
7794
[dynamically sized types]: ../dynamically-sized-types.md
95+
[metadata]: dynamic-sized.pointer-types
96+
[pointer-to-pointer cast]: expr.as.pointer
7897
[size zero]: glossary.zst
98+
[unsized tail]: dynamic-sized.tail
7999
[temporary value]: ../expressions.md#temporaries
100+
[trait object upcast]: coerce.unsize.trait-upcast
101+
[unsized coercion]: coerce.unsize

0 commit comments

Comments
 (0)