@mjbshaw ah, const fn
is a very tough additional constraint. Your code looks a lot like what memoffset
had! It also used to support const fn
. And transmuting 0
into a reference causes SIGILL on some platforms.
Could you try to use mem::align_of::<$parent>()
instead of 0? That would be slightly less UB. In fact that would make it basically equivalent to the pre-
MaybeUninit
version that is currently in memoffset
.
And you could also force evaluation to happen at CTFE, thereby avoiding run-time trouble:
macro_rules! offset_of {
($parent:tt, $field:tt) => {{
// Make sure the field actually exists. This line ensures that a
// compile-time error is generated if $field is accessed through a
// Deref impl.
let $parent { $field: _, .. };
// FORCING code to be const-eval'ed so that it can
// not cause run-time trouble.
const OFFSET: usize = {
union TransmuteHack<T: Copy, U: Copy> {
from: T,
to: U,
}
unsafe {
TransmuteHack::<_, usize> {
from: &TransmuteHack::<usize, &'static $parent> {
// Properly aligned to maintain at least *some*
// properties of a valid reference.
from: std::mem::align_of::<$parent>(),
}.to.$field,
}.to - std::mem::align_of::<$parent>()
}
};
OFFSET
}}
}
I also added Deref-coercion-protection.
Here's a small test of this on the playground.