This example should do one of these three things, but it doesn't (playground):
- compile successfully (
PADDED == FILLED after all, field-wise)
- error on
FILLED's definition (due to evaluated constant not fitting type)
- error when
FILLED is used as an argument to Phantom
#![feature(const_generics)]
union Transmute<T: Copy, U: Copy> {
from: T,
to: U,
}
const PADDED: (u8, u16) = (0, 0);
const FILLED: (u8, u16) = unsafe { Transmute { from: [0u8; 4] }.to };
struct Phantom<const X: (u8, u16)>;
fn test(x: Phantom<PADDED>) -> Phantom<FILLED> {
x
}
Instead, Phantom<PADDED> and Phantom<FILLED> are considered different types.
If we want to make it compile, we could normalize FILLED to also have that padding byte marked as "undef", but I'm not sure if we can do this normalization if the values were behind a reference.
So we might want to error if e.g. &[0u8; 4] was transmuted to &(u8, u16), because normalizing it would change what runtime code would see. Again, we have two places where we can error.
If we want to error without causing no breaking changes, either always or just indirect case, we can do so by introducing a second, stricter, validity check in ty::Const Well-Formed rules (which we should be able to post-#70107).
That check should enforce that the value is a tree of constructors (&_ would be treated as a constructor) with integer leaves (no relocations, i.e. no raw/fn pointers), where any user ADTs are structurally-matchable, and all padding bytes (not occupied by leaves) are "undef".
cc @rust-lang/wg-const-eval @varkor @yodaldevoid
This example should do one of these three things, but it doesn't (playground):
PADDED == FILLEDafter all, field-wise)FILLED's definition (due to evaluated constant not fitting type)FILLEDis used as an argument toPhantomInstead,
Phantom<PADDED>andPhantom<FILLED>are considered different types.If we want to make it compile, we could normalize
FILLEDto also have that padding byte marked as "undef", but I'm not sure if we can do this normalization if the values were behind a reference.So we might want to error if e.g.
&[0u8; 4]was transmuted to&(u8, u16), because normalizing it would change what runtime code would see. Again, we have two places where we can error.If we want to error without causing no breaking changes, either always or just indirect case, we can do so by introducing a second, stricter, validity check in
ty::ConstWell-Formed rules (which we should be able to post-#70107).That check should enforce that the value is a tree of constructors (
&_would be treated as a constructor) with integer leaves (no relocations, i.e. no raw/fnpointers), where any user ADTs are structurally-matchable, and all padding bytes (not occupied by leaves) are "undef".cc @rust-lang/wg-const-eval @varkor @yodaldevoid