in library/core/src/marker.rs:
/// A marker type without a compile-time or runtime defined size.
///
/// This is distinct from other dynamically-sized types as it does not have
/// pointer metadata. References/pointers to slices (`[T]`) and trait objects
/// (`dyn Trait`) carry extra metadata (length for slices, vtable pointer for
/// trait objects).
///
/// This is useful for creating immovable structs, or structs with trailing data.
///
/// Example:
///
/// ```rust
/// pub struct MyImmovableType {
/// a: u32,
/// b: f64,
/// c: String,
/// _unsized: PhantomUnsized,
/// }
///
/// // ...
///
/// // A reference to `MyImmovableType` is "thin" like references to sized types.
/// assert_eq!(size_of::<&MyImmovableType>(), size_of::<&()>());
/// ```
pub extern type PhantomUnsized;
and to make it possible to construct these immovable types,
in library/core/src/mem/mod.rs:
/// Return the minimum size of a type in bytes.
///
/// For unsized types, this is the size of the "leading" data before the unsized
/// field. For sized types, this is equivalent to [`size_of`].
///
/// ```rust
/// pub struct MyTypeWithDST<T: ?Sized> {
/// a: u32,
/// b: f64,
/// trailer: T,
/// }
///
/// assert_eq!(min_size_of::<MyTypeWithDST<[u32]>>(), 16);
/// assert_eq!(min_size_of::<MyTypeWithDST<dyn Trait>>(), 16);
/// assert_eq!(min_size_of::<MyTypeWithDST<PhantomUnsized>>(), 16);
/// ```
pub const fn min_size_of<T: ?Sized>() -> usize;
// `min_align_of` is not needed as `align_of` already returns "the ABI-required
// minimum alignment of a type". However, the type parameter on `align_of` needs
// to be relaxed to `?Sized`. The documentation needs to be updated to specify
// the behavior of `dyn Trait` since the actual alignment is defined at runtime.
// The trait bound on `size_of` must be changed from `T: ?Sized` to
// `T: ?MetaSized` so `size_of::<PhantomUnsized>()` results in a compiler error.
This replaces extern type; developers would use a newtype instead:
pub struct MyExternType(PhantomUnsized);
Attempting to "move" a runtime-unsized type with std::ptr::copy_nonoverlapping is generally undefined behavior except when library invariants are satisfied. For example, a "packet" type with a size field and trailing bytes cannot be moved safely by another other library because its invariants (presence of trailing bytes within its allocation) may be violated.
References to runtime-unsized types will not have the dereferenceable LLVM attribute (or maybe they could if it isn't UB to read past the end of a dereferenceable ptr).