Open
Description
An asserting const within a trait impl will trigger a late-monomorphization error. This can be used to directly check for uninit bytes.
This should be opt-in in the derive trait. For manual implementations a helper macro could provide the same field checks.
Please note that this implementation is was written in a couple of minutes, so it may have unforeseen issues.
unsafe trait NoUninit {
// Asserts fields are aligned, returns alignment
const FIELDS_ALIGNED: usize;
}
unsafe impl NoUninit for u8 {
const FIELDS_ALIGNED: usize = std::mem::align_of::<Self>();
}
unsafe impl NoUninit for u16 {
const FIELDS_ALIGNED: usize = std::mem::align_of::<Self>();
}
unsafe impl<const N: usize, T: NoUninit> NoUninit for [T; N] {
const FIELDS_ALIGNED: usize = <T as NoUninit>::FIELDS_ALIGNED;
}
#[repr(C)]
struct MaybeNoUninit<T> {
byte: u8,
payload: T,
}
unsafe impl<T: NoUninit> NoUninit for MaybeNoUninit<T> {
const FIELDS_ALIGNED: usize = {
let mut offset = 0;
let field_align = <u8 as NoUninit>::FIELDS_ALIGNED;
offset += std::mem::size_of::<u8>();
offset = (offset + (field_align - 1)) & !(field_align - 1);
let field_align = <T as NoUninit>::FIELDS_ALIGNED;
assert!((offset & (field_align - 1)) == 0, "`payload` is misaligned, `byte` has a smaller alignment");
offset += std::mem::size_of::<u8>();
offset = (offset + (field_align - 1)) & !(field_align - 1);
let struct_align = std::mem::align_of::<T>();
assert!((offset & (struct_align - 1)) == 0, "struct has trailing padding bytes");
struct_align
};
}
fn main() {
// These are fine:
let _ = <MaybeNoUninit<u8> as NoUninit>::FIELDS_ALIGNED;
let _ = <MaybeNoUninit<[u8; 2]> as NoUninit>::FIELDS_ALIGNED;
let _ = <MaybeNoUninit<[[u8; 2]; 8]> as NoUninit>::FIELDS_ALIGNED;
// Causes late-mono error:
let _ = <MaybeNoUninit<u16> as NoUninit>::FIELDS_ALIGNED;
}