Add test to check order of repr(int) enum fields
RFC #2195 specifies that a repr(int) enum such as: #[repr(u8)] enum MyEnum { B { x: u8, y: i16, z: u8 }, } has a layout that is equivalent to: #[repr(C)] enum MyEnumVariantB { tag: u8, x: u8, y: i16, z: u8 }, However this isn't actually implemented, with the actual layout being roughly equivalent to: union MyEnumPayload { B { x: u8, y: i16, z: u8 }, } #[repr(packed)] struct MyEnum { tag: u8, payload: MyEnumPayload, } Thus the variant payload is *not* subject to repr(C) ordering rules, and gets re-ordered as `{ x: u8, z: u8, z: i16 }` The existing tests added in pull-req #45688 fail to catch this as the repr(C) ordering just happens to match the current Rust ordering in this case; adding a third field reveals the problem.
This commit is contained in:
parent
fba23d01d1
commit
d84bdba728
3 changed files with 30 additions and 24 deletions
|
@ -20,11 +20,12 @@ use std::mem;
|
||||||
#[repr(C, u8)]
|
#[repr(C, u8)]
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||||
enum MyEnum {
|
enum MyEnum {
|
||||||
A(u32), // Single primitive value
|
A(u32), // Single primitive value
|
||||||
B { x: u8, y: i16 }, // Composite, and the offset of `y` depends on tag being internal
|
B { x: u8, y: i16, z: u8 }, // Composite, and the offsets of `y` and `z`
|
||||||
C, // Empty
|
// depend on tag being internal
|
||||||
D(Option<u32>), // Contains an enum
|
C, // Empty
|
||||||
E(Duration), // Contains a struct
|
D(Option<u32>), // Contains an enum
|
||||||
|
E(Duration), // Contains a struct
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
@ -44,14 +45,14 @@ union MyEnumPayload {
|
||||||
|
|
||||||
#[repr(u8)] #[derive(Copy, Clone)] enum MyEnumTag { A, B, C, D, E }
|
#[repr(u8)] #[derive(Copy, Clone)] enum MyEnumTag { A, B, C, D, E }
|
||||||
#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantA(u32);
|
#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantA(u32);
|
||||||
#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantB {x: u8, y: i16 }
|
#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantB {x: u8, y: i16, z: u8 }
|
||||||
#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantD(Option<u32>);
|
#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantD(Option<u32>);
|
||||||
#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantE(Duration);
|
#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantE(Duration);
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let result: Vec<Result<MyEnum, ()>> = vec![
|
let result: Vec<Result<MyEnum, ()>> = vec![
|
||||||
Ok(MyEnum::A(17)),
|
Ok(MyEnum::A(17)),
|
||||||
Ok(MyEnum::B { x: 206, y: 1145 }),
|
Ok(MyEnum::B { x: 206, y: 1145, z: 78 }),
|
||||||
Ok(MyEnum::C),
|
Ok(MyEnum::C),
|
||||||
Err(()),
|
Err(()),
|
||||||
Ok(MyEnum::D(Some(407))),
|
Ok(MyEnum::D(Some(407))),
|
||||||
|
@ -63,7 +64,7 @@ fn main() {
|
||||||
// Binary serialized version of the above (little-endian)
|
// Binary serialized version of the above (little-endian)
|
||||||
let input: Vec<u8> = vec![
|
let input: Vec<u8> = vec![
|
||||||
0, 17, 0, 0, 0,
|
0, 17, 0, 0, 0,
|
||||||
1, 206, 121, 4,
|
1, 206, 121, 4, 78,
|
||||||
2,
|
2,
|
||||||
8, /* invalid tag value */
|
8, /* invalid tag value */
|
||||||
3, 0, 151, 1, 0, 0,
|
3, 0, 151, 1, 0, 0,
|
||||||
|
@ -112,6 +113,7 @@ fn parse_my_enum<'a>(dest: &'a mut MyEnum, buf: &mut &[u8]) -> Result<(), ()> {
|
||||||
MyEnumTag::B => {
|
MyEnumTag::B => {
|
||||||
dest.payload.B.x = read_u8(buf)?;
|
dest.payload.B.x = read_u8(buf)?;
|
||||||
dest.payload.B.y = read_u16_le(buf)? as i16;
|
dest.payload.B.y = read_u16_le(buf)? as i16;
|
||||||
|
dest.payload.B.z = read_u8(buf)?;
|
||||||
}
|
}
|
||||||
MyEnumTag::C => {
|
MyEnumTag::C => {
|
||||||
/* do nothing */
|
/* do nothing */
|
||||||
|
|
|
@ -20,11 +20,12 @@ use std::mem;
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||||
enum MyEnum {
|
enum MyEnum {
|
||||||
A(u32), // Single primitive value
|
A(u32), // Single primitive value
|
||||||
B { x: u8, y: i16 }, // Composite, and the offset of `y` depends on tag being internal
|
B { x: u8, y: i16, z: u8 }, // Composite, and the offset of `y` and `z`
|
||||||
C, // Empty
|
// depend on tag being internal
|
||||||
D(Option<u32>), // Contains an enum
|
C, // Empty
|
||||||
E(Duration), // Contains a struct
|
D(Option<u32>), // Contains an enum
|
||||||
|
E(Duration), // Contains a struct
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
@ -44,14 +45,14 @@ union MyEnumPayload {
|
||||||
|
|
||||||
#[repr(C)] #[derive(Copy, Clone)] enum MyEnumTag { A, B, C, D, E }
|
#[repr(C)] #[derive(Copy, Clone)] enum MyEnumTag { A, B, C, D, E }
|
||||||
#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantA(u32);
|
#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantA(u32);
|
||||||
#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantB {x: u8, y: i16 }
|
#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantB {x: u8, y: i16, z: u8 }
|
||||||
#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantD(Option<u32>);
|
#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantD(Option<u32>);
|
||||||
#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantE(Duration);
|
#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantE(Duration);
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let result: Vec<Result<MyEnum, ()>> = vec![
|
let result: Vec<Result<MyEnum, ()>> = vec![
|
||||||
Ok(MyEnum::A(17)),
|
Ok(MyEnum::A(17)),
|
||||||
Ok(MyEnum::B { x: 206, y: 1145 }),
|
Ok(MyEnum::B { x: 206, y: 1145, z: 78 }),
|
||||||
Ok(MyEnum::C),
|
Ok(MyEnum::C),
|
||||||
Err(()),
|
Err(()),
|
||||||
Ok(MyEnum::D(Some(407))),
|
Ok(MyEnum::D(Some(407))),
|
||||||
|
@ -63,7 +64,7 @@ fn main() {
|
||||||
// Binary serialized version of the above (little-endian)
|
// Binary serialized version of the above (little-endian)
|
||||||
let input: Vec<u8> = vec![
|
let input: Vec<u8> = vec![
|
||||||
0, 17, 0, 0, 0,
|
0, 17, 0, 0, 0,
|
||||||
1, 206, 121, 4,
|
1, 206, 121, 4, 78,
|
||||||
2,
|
2,
|
||||||
8, /* invalid tag value */
|
8, /* invalid tag value */
|
||||||
3, 0, 151, 1, 0, 0,
|
3, 0, 151, 1, 0, 0,
|
||||||
|
@ -112,6 +113,7 @@ fn parse_my_enum<'a>(dest: &'a mut MyEnum, buf: &mut &[u8]) -> Result<(), ()> {
|
||||||
MyEnumTag::B => {
|
MyEnumTag::B => {
|
||||||
dest.payload.B.x = read_u8(buf)?;
|
dest.payload.B.x = read_u8(buf)?;
|
||||||
dest.payload.B.y = read_u16_le(buf)? as i16;
|
dest.payload.B.y = read_u16_le(buf)? as i16;
|
||||||
|
dest.payload.B.z = read_u8(buf)?;
|
||||||
}
|
}
|
||||||
MyEnumTag::C => {
|
MyEnumTag::C => {
|
||||||
/* do nothing */
|
/* do nothing */
|
||||||
|
|
|
@ -20,11 +20,12 @@ use std::mem;
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||||
enum MyEnum {
|
enum MyEnum {
|
||||||
A(u32), // Single primitive value
|
A(u32), // Single primitive value
|
||||||
B { x: u8, y: i16 }, // Composite, and the offset of `y` depends on tag being internal
|
B { x: u8, y: i16, z: u8 }, // Composite, and the offset of `y` and `z`
|
||||||
C, // Empty
|
// depend on tag being internal
|
||||||
D(Option<u32>), // Contains an enum
|
C, // Empty
|
||||||
E(Duration), // Contains a struct
|
D(Option<u32>), // Contains an enum
|
||||||
|
E(Duration), // Contains a struct
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
|
@ -39,7 +40,7 @@ union MyEnumRepr {
|
||||||
|
|
||||||
#[repr(u8)] #[derive(Copy, Clone)] enum MyEnumTag { A, B, C, D, E }
|
#[repr(u8)] #[derive(Copy, Clone)] enum MyEnumTag { A, B, C, D, E }
|
||||||
#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantA(MyEnumTag, u32);
|
#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantA(MyEnumTag, u32);
|
||||||
#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantB { tag: MyEnumTag, x: u8, y: i16 }
|
#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantB { tag: MyEnumTag, x: u8, y: i16, z: u8 }
|
||||||
#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantC(MyEnumTag);
|
#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantC(MyEnumTag);
|
||||||
#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantD(MyEnumTag, Option<u32>);
|
#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantD(MyEnumTag, Option<u32>);
|
||||||
#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantE(MyEnumTag, Duration);
|
#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantE(MyEnumTag, Duration);
|
||||||
|
@ -47,7 +48,7 @@ union MyEnumRepr {
|
||||||
fn main() {
|
fn main() {
|
||||||
let result: Vec<Result<MyEnum, ()>> = vec![
|
let result: Vec<Result<MyEnum, ()>> = vec![
|
||||||
Ok(MyEnum::A(17)),
|
Ok(MyEnum::A(17)),
|
||||||
Ok(MyEnum::B { x: 206, y: 1145 }),
|
Ok(MyEnum::B { x: 206, y: 1145, z: 78 }),
|
||||||
Ok(MyEnum::C),
|
Ok(MyEnum::C),
|
||||||
Err(()),
|
Err(()),
|
||||||
Ok(MyEnum::D(Some(407))),
|
Ok(MyEnum::D(Some(407))),
|
||||||
|
@ -59,7 +60,7 @@ fn main() {
|
||||||
// Binary serialized version of the above (little-endian)
|
// Binary serialized version of the above (little-endian)
|
||||||
let input: Vec<u8> = vec![
|
let input: Vec<u8> = vec![
|
||||||
0, 17, 0, 0, 0,
|
0, 17, 0, 0, 0,
|
||||||
1, 206, 121, 4,
|
1, 206, 121, 4, 78,
|
||||||
2,
|
2,
|
||||||
8, /* invalid tag value */
|
8, /* invalid tag value */
|
||||||
3, 0, 151, 1, 0, 0,
|
3, 0, 151, 1, 0, 0,
|
||||||
|
@ -108,6 +109,7 @@ fn parse_my_enum<'a>(dest: &'a mut MyEnum, buf: &mut &[u8]) -> Result<(), ()> {
|
||||||
MyEnumTag::B => {
|
MyEnumTag::B => {
|
||||||
dest.B.x = read_u8(buf)?;
|
dest.B.x = read_u8(buf)?;
|
||||||
dest.B.y = read_u16_le(buf)? as i16;
|
dest.B.y = read_u16_le(buf)? as i16;
|
||||||
|
dest.B.z = read_u8(buf)?;
|
||||||
}
|
}
|
||||||
MyEnumTag::C => {
|
MyEnumTag::C => {
|
||||||
/* do nothing */
|
/* do nothing */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue