Skip to content

Commit 8b80890

Browse files
committed
Add (failing) test to check order of repr(int) enum fields
RFC rust-lang#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 rust-lang#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.
1 parent 4a45578 commit 8b80890

File tree

3 files changed

+27
-24
lines changed

3 files changed

+27
-24
lines changed

src/test/run-pass/structs-enums/enum-non-c-like-repr-c-and-int.rs

+9-8
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ use std::mem;
2020
#[repr(C, u8)]
2121
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
2222
enum MyEnum {
23-
A(u32), // Single primitive value
24-
B { x: u8, y: i16 }, // Composite, and the offset of `y` depends on tag being internal
25-
C, // Empty
26-
D(Option<u32>), // Contains an enum
27-
E(Duration), // Contains a struct
23+
A(u32), // Single primitive value
24+
B { x: u8, y: i16, z: u8 }, // Composite, and the offset of `y` and `z` depend on tag being internal
25+
C, // Empty
26+
D(Option<u32>), // Contains an enum
27+
E(Duration), // Contains a struct
2828
}
2929

3030
#[repr(C)]
@@ -44,14 +44,14 @@ union MyEnumPayload {
4444

4545
#[repr(u8)] #[derive(Copy, Clone)] enum MyEnumTag { A, B, C, D, E }
4646
#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantA(u32);
47-
#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantB {x: u8, y: i16 }
47+
#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantB {x: u8, y: i16, z: u8 }
4848
#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantD(Option<u32>);
4949
#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantE(Duration);
5050

5151
fn main() {
5252
let result: Vec<Result<MyEnum, ()>> = vec![
5353
Ok(MyEnum::A(17)),
54-
Ok(MyEnum::B { x: 206, y: 1145 }),
54+
Ok(MyEnum::B { x: 206, y: 1145, z: 78 }),
5555
Ok(MyEnum::C),
5656
Err(()),
5757
Ok(MyEnum::D(Some(407))),
@@ -63,7 +63,7 @@ fn main() {
6363
// Binary serialized version of the above (little-endian)
6464
let input: Vec<u8> = vec![
6565
0, 17, 0, 0, 0,
66-
1, 206, 121, 4,
66+
1, 206, 121, 4, 78,
6767
2,
6868
8, /* invalid tag value */
6969
3, 0, 151, 1, 0, 0,
@@ -112,6 +112,7 @@ fn parse_my_enum<'a>(dest: &'a mut MyEnum, buf: &mut &[u8]) -> Result<(), ()> {
112112
MyEnumTag::B => {
113113
dest.payload.B.x = read_u8(buf)?;
114114
dest.payload.B.y = read_u16_le(buf)? as i16;
115+
dest.payload.B.z = read_u8(buf)?;
115116
}
116117
MyEnumTag::C => {
117118
/* do nothing */

src/test/run-pass/structs-enums/enum-non-c-like-repr-c.rs

+9-8
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ use std::mem;
2020
#[repr(C)]
2121
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
2222
enum MyEnum {
23-
A(u32), // Single primitive value
24-
B { x: u8, y: i16 }, // Composite, and the offset of `y` depends on tag being internal
25-
C, // Empty
26-
D(Option<u32>), // Contains an enum
27-
E(Duration), // Contains a struct
23+
A(u32), // Single primitive value
24+
B { x: u8, y: i16, z: u8 }, // Composite, and the offset of `y` and `z` depend on tag being internal
25+
C, // Empty
26+
D(Option<u32>), // Contains an enum
27+
E(Duration), // Contains a struct
2828
}
2929

3030
#[repr(C)]
@@ -44,14 +44,14 @@ union MyEnumPayload {
4444

4545
#[repr(C)] #[derive(Copy, Clone)] enum MyEnumTag { A, B, C, D, E }
4646
#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantA(u32);
47-
#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantB {x: u8, y: i16 }
47+
#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantB {x: u8, y: i16, z: u8 }
4848
#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantD(Option<u32>);
4949
#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantE(Duration);
5050

5151
fn main() {
5252
let result: Vec<Result<MyEnum, ()>> = vec![
5353
Ok(MyEnum::A(17)),
54-
Ok(MyEnum::B { x: 206, y: 1145 }),
54+
Ok(MyEnum::B { x: 206, y: 1145, z: 78 }),
5555
Ok(MyEnum::C),
5656
Err(()),
5757
Ok(MyEnum::D(Some(407))),
@@ -63,7 +63,7 @@ fn main() {
6363
// Binary serialized version of the above (little-endian)
6464
let input: Vec<u8> = vec![
6565
0, 17, 0, 0, 0,
66-
1, 206, 121, 4,
66+
1, 206, 121, 4, 78,
6767
2,
6868
8, /* invalid tag value */
6969
3, 0, 151, 1, 0, 0,
@@ -112,6 +112,7 @@ fn parse_my_enum<'a>(dest: &'a mut MyEnum, buf: &mut &[u8]) -> Result<(), ()> {
112112
MyEnumTag::B => {
113113
dest.payload.B.x = read_u8(buf)?;
114114
dest.payload.B.y = read_u16_le(buf)? as i16;
115+
dest.payload.B.z = read_u8(buf)?;
115116
}
116117
MyEnumTag::C => {
117118
/* do nothing */

src/test/run-pass/structs-enums/enum-non-c-like-repr-int.rs

+9-8
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ use std::mem;
2020
#[repr(u8)]
2121
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
2222
enum MyEnum {
23-
A(u32), // Single primitive value
24-
B { x: u8, y: i16 }, // Composite, and the offset of `y` depends on tag being internal
25-
C, // Empty
26-
D(Option<u32>), // Contains an enum
27-
E(Duration), // Contains a struct
23+
A(u32), // Single primitive value
24+
B { x: u8, y: i16, z: u8 }, // Composite, and the offset of `y` and `z` depend on tag being internal
25+
C, // Empty
26+
D(Option<u32>), // Contains an enum
27+
E(Duration), // Contains a struct
2828
}
2929

3030
#[allow(non_snake_case)]
@@ -39,15 +39,15 @@ union MyEnumRepr {
3939

4040
#[repr(u8)] #[derive(Copy, Clone)] enum MyEnumTag { A, B, C, D, E }
4141
#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantA(MyEnumTag, u32);
42-
#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantB { tag: MyEnumTag, x: u8, y: i16 }
42+
#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantB { tag: MyEnumTag, x: u8, y: i16, z: u8 }
4343
#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantC(MyEnumTag);
4444
#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantD(MyEnumTag, Option<u32>);
4545
#[repr(C)] #[derive(Copy, Clone)] struct MyEnumVariantE(MyEnumTag, Duration);
4646

4747
fn main() {
4848
let result: Vec<Result<MyEnum, ()>> = vec![
4949
Ok(MyEnum::A(17)),
50-
Ok(MyEnum::B { x: 206, y: 1145 }),
50+
Ok(MyEnum::B { x: 206, y: 1145, z: 78 }),
5151
Ok(MyEnum::C),
5252
Err(()),
5353
Ok(MyEnum::D(Some(407))),
@@ -59,7 +59,7 @@ fn main() {
5959
// Binary serialized version of the above (little-endian)
6060
let input: Vec<u8> = vec![
6161
0, 17, 0, 0, 0,
62-
1, 206, 121, 4,
62+
1, 206, 121, 4, 78,
6363
2,
6464
8, /* invalid tag value */
6565
3, 0, 151, 1, 0, 0,
@@ -108,6 +108,7 @@ fn parse_my_enum<'a>(dest: &'a mut MyEnum, buf: &mut &[u8]) -> Result<(), ()> {
108108
MyEnumTag::B => {
109109
dest.B.x = read_u8(buf)?;
110110
dest.B.y = read_u16_le(buf)? as i16;
111+
dest.B.z = read_u8(buf)?;
111112
}
112113
MyEnumTag::C => {
113114
/* do nothing */

0 commit comments

Comments
 (0)