diff options
| author | Peter Todd <pete@petertodd.org> | 2018-12-07 19:54:16 -0500 |
|---|---|---|
| committer | Emilio Cobos Álvarez <emilio@crisal.io> | 2018-12-16 20:36:25 +0100 |
| commit | d84bdba72888a42a67c1771b0a62f8517c8964cb (patch) | |
| tree | 54c21cb914fb46e77324de1c7f8ce4247e1accc4 | |
| parent | fba23d01d16db8b83b2415bc538d2a850fcf24da (diff) | |
| download | rust-d84bdba72888a42a67c1771b0a62f8517c8964cb.tar.gz rust-d84bdba72888a42a67c1771b0a62f8517c8964cb.zip | |
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.
3 files changed, 30 insertions, 24 deletions
diff --git a/src/test/run-pass/structs-enums/enum-non-c-like-repr-c-and-int.rs b/src/test/run-pass/structs-enums/enum-non-c-like-repr-c-and-int.rs index 14eac687ecf..f59f100653f 100644 --- a/src/test/run-pass/structs-enums/enum-non-c-like-repr-c-and-int.rs +++ b/src/test/run-pass/structs-enums/enum-non-c-like-repr-c-and-int.rs @@ -20,11 +20,12 @@ use std::mem; #[repr(C, u8)] #[derive(Copy, Clone, Eq, PartialEq, Debug)] enum MyEnum { - A(u32), // Single primitive value - B { x: u8, y: i16 }, // Composite, and the offset of `y` depends on tag being internal - C, // Empty - D(Option<u32>), // Contains an enum - E(Duration), // Contains a struct + A(u32), // Single primitive value + B { x: u8, y: i16, z: u8 }, // Composite, and the offsets of `y` and `z` + // depend on tag being internal + C, // Empty + D(Option<u32>), // Contains an enum + E(Duration), // Contains a struct } #[repr(C)] @@ -44,14 +45,14 @@ union MyEnumPayload { #[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 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 MyEnumVariantE(Duration); fn main() { let result: Vec<Result<MyEnum, ()>> = vec![ Ok(MyEnum::A(17)), - Ok(MyEnum::B { x: 206, y: 1145 }), + Ok(MyEnum::B { x: 206, y: 1145, z: 78 }), Ok(MyEnum::C), Err(()), Ok(MyEnum::D(Some(407))), @@ -63,7 +64,7 @@ fn main() { // Binary serialized version of the above (little-endian) let input: Vec<u8> = vec![ 0, 17, 0, 0, 0, - 1, 206, 121, 4, + 1, 206, 121, 4, 78, 2, 8, /* invalid tag value */ 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 => { dest.payload.B.x = read_u8(buf)?; dest.payload.B.y = read_u16_le(buf)? as i16; + dest.payload.B.z = read_u8(buf)?; } MyEnumTag::C => { /* do nothing */ diff --git a/src/test/run-pass/structs-enums/enum-non-c-like-repr-c.rs b/src/test/run-pass/structs-enums/enum-non-c-like-repr-c.rs index 80c4339af9d..e88b91ab6c3 100644 --- a/src/test/run-pass/structs-enums/enum-non-c-like-repr-c.rs +++ b/src/test/run-pass/structs-enums/enum-non-c-like-repr-c.rs @@ -20,11 +20,12 @@ use std::mem; #[repr(C)] #[derive(Copy, Clone, Eq, PartialEq, Debug)] enum MyEnum { - A(u32), // Single primitive value - B { x: u8, y: i16 }, // Composite, and the offset of `y` depends on tag being internal - C, // Empty - D(Option<u32>), // Contains an enum - E(Duration), // Contains a struct + A(u32), // Single primitive value + B { x: u8, y: i16, z: u8 }, // Composite, and the offset of `y` and `z` + // depend on tag being internal + C, // Empty + D(Option<u32>), // Contains an enum + E(Duration), // Contains a struct } #[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)] 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 MyEnumVariantE(Duration); fn main() { let result: Vec<Result<MyEnum, ()>> = vec![ Ok(MyEnum::A(17)), - Ok(MyEnum::B { x: 206, y: 1145 }), + Ok(MyEnum::B { x: 206, y: 1145, z: 78 }), Ok(MyEnum::C), Err(()), Ok(MyEnum::D(Some(407))), @@ -63,7 +64,7 @@ fn main() { // Binary serialized version of the above (little-endian) let input: Vec<u8> = vec![ 0, 17, 0, 0, 0, - 1, 206, 121, 4, + 1, 206, 121, 4, 78, 2, 8, /* invalid tag value */ 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 => { dest.payload.B.x = read_u8(buf)?; dest.payload.B.y = read_u16_le(buf)? as i16; + dest.payload.B.z = read_u8(buf)?; } MyEnumTag::C => { /* do nothing */ diff --git a/src/test/run-pass/structs-enums/enum-non-c-like-repr-int.rs b/src/test/run-pass/structs-enums/enum-non-c-like-repr-int.rs index 4c1fe8db1cd..d862c0c72c2 100644 --- a/src/test/run-pass/structs-enums/enum-non-c-like-repr-int.rs +++ b/src/test/run-pass/structs-enums/enum-non-c-like-repr-int.rs @@ -20,11 +20,12 @@ use std::mem; #[repr(u8)] #[derive(Copy, Clone, Eq, PartialEq, Debug)] enum MyEnum { - A(u32), // Single primitive value - B { x: u8, y: i16 }, // Composite, and the offset of `y` depends on tag being internal - C, // Empty - D(Option<u32>), // Contains an enum - E(Duration), // Contains a struct + A(u32), // Single primitive value + B { x: u8, y: i16, z: u8 }, // Composite, and the offset of `y` and `z` + // depend on tag being internal + C, // Empty + D(Option<u32>), // Contains an enum + E(Duration), // Contains a struct } #[allow(non_snake_case)] @@ -39,7 +40,7 @@ union MyEnumRepr { #[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 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 MyEnumVariantD(MyEnumTag, Option<u32>); #[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantE(MyEnumTag, Duration); @@ -47,7 +48,7 @@ union MyEnumRepr { fn main() { let result: Vec<Result<MyEnum, ()>> = vec![ Ok(MyEnum::A(17)), - Ok(MyEnum::B { x: 206, y: 1145 }), + Ok(MyEnum::B { x: 206, y: 1145, z: 78 }), Ok(MyEnum::C), Err(()), Ok(MyEnum::D(Some(407))), @@ -59,7 +60,7 @@ fn main() { // Binary serialized version of the above (little-endian) let input: Vec<u8> = vec![ 0, 17, 0, 0, 0, - 1, 206, 121, 4, + 1, 206, 121, 4, 78, 2, 8, /* invalid tag value */ 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 => { dest.B.x = read_u8(buf)?; dest.B.y = read_u16_le(buf)? as i16; + dest.B.z = read_u8(buf)?; } MyEnumTag::C => { /* do nothing */ |
