Repr[u8], std::mem::size_of

 #[repr(u8)]
pub enum L0 {
    A,
    B,
    C,
}

#[repr(u8)]
pub enum L1 {
    A(L0),
    B(L0),
    C(L0),
}

#[repr(u8)]
pub enum L2 {
    A(L1),
    B(L1),
    C(L1),
}

#[test]
pub fn test() {
    println!("size: {:?}", std::mem::size_of::<L2>())
}

This code prints out 3. Which is reasonable. Here is the part I am confused on: why is the repr(u8) not throwing an error if L2 has size 3 bytes instead of 1 byte ?

#[repr(u*)] and #[repr(i*)] on enums with field variants are equivalent to making the enum #[repr(C)], where the fieldless enum used as discriminant of the generated union is marked #[repr(u*)] or #[repr(i*)]. You'll still get an error if you define too many variants.

2 Likes

Documentation you might find helpful:

3 Likes

This is correct for #[repr(C,i*)] enums, but #[repr(i*)] enums are a union of #[repr(C)] (discriminant, payload) structures instead. What this means in practice is that #[repr(i*)] enums can be more tightly packed at the expense of having the payload location dependent on the variant:

#[repr(u8)] enum ReprInt {
    A(u32),
    B([u8;7])
}

#[repr(C,u8)] enum ReprCInt {
    A(u32),
    B([u8;7])
}

fn main() {
    dbg!(std::mem::size_of::<ReprInt>());   //  8
    dbg!(std::mem::size_of::<ReprCInt>());  // 12
}
1 Like