diff --git a/src/test/auxiliary/rust_test_helpers.c b/src/test/auxiliary/rust_test_helpers.c index b95b0ca1a89..a5299638e52 100644 --- a/src/test/auxiliary/rust_test_helpers.c +++ b/src/test/auxiliary/rust_test_helpers.c @@ -300,3 +300,87 @@ __int128 sub(__int128 a, __int128 b) { } #endif + +#define OPTION_TAG_NONE (0) +#define OPTION_TAG_SOME (1) + +struct U8TaggedEnumOptionU64 { + uint8_t tag; + union { + uint64_t some; + }; +}; + +struct U8TaggedEnumOptionU64 +rust_dbg_new_some_u64(uint64_t some) { + struct U8TaggedEnumOptionU64 r = { + .tag = OPTION_TAG_SOME, + .some = some, + }; + return r; +} + +struct U8TaggedEnumOptionU64 +rust_dbg_new_none_u64(void) { + struct U8TaggedEnumOptionU64 r = { + .tag = OPTION_TAG_NONE, + }; + return r; +} + +int32_t +rust_dbg_unpack_option_u64(struct U8TaggedEnumOptionU64 o, uint64_t *into) { + assert(into); + switch (o.tag) { + case OPTION_TAG_SOME: + *into = o.some; + return 1; + case OPTION_TAG_NONE: + return 0; + default: + assert(0 && "unexpected tag"); + } +} + +struct U8TaggedEnumOptionU64U64 { + uint8_t tag; + union { + struct { + uint64_t a; + uint64_t b; + } some; + }; +}; + +struct U8TaggedEnumOptionU64U64 +rust_dbg_new_some_u64u64(uint64_t a, uint64_t b) { + struct U8TaggedEnumOptionU64U64 r = { + .tag = OPTION_TAG_SOME, + .some = { .a = a, .b = b }, + }; + return r; +} + +struct U8TaggedEnumOptionU64U64 +rust_dbg_new_none_u64u64(void) { + struct U8TaggedEnumOptionU64U64 r = { + .tag = OPTION_TAG_NONE, + }; + return r; +} + +int32_t +rust_dbg_unpack_option_u64u64(struct U8TaggedEnumOptionU64U64 o, uint64_t *a, uint64_t *b) { + assert(a); + assert(b); + switch (o.tag) { + case OPTION_TAG_SOME: + *a = o.some.a; + *b = o.some.b; + return 1; + case OPTION_TAG_NONE: + return 0; + default: + assert(0 && "unexpected tag"); + } +} diff --git a/src/test/ui/abi/abi-sysv64-arg-passing.rs b/src/test/ui/abi/abi-sysv64-arg-passing.rs index d40006eb9b6..adb62ab698e 100644 --- a/src/test/ui/abi/abi-sysv64-arg-passing.rs +++ b/src/test/ui/abi/abi-sysv64-arg-passing.rs @@ -92,6 +92,18 @@ mod tests { #[derive(Copy, Clone)] pub struct Floats { a: f64, b: u8, c: f64 } + #[repr(C, u8)] + pub enum U8TaggedEnumOptionU64U64 { + None, + Some(u64,u64), + } + + #[repr(C, u8)] + pub enum U8TaggedEnumOptionU64 { + None, + Some(u64), + } + #[link(name = "rust_test_helpers", kind = "static")] extern "sysv64" { pub fn rust_int8_to_int32(_: i8) -> i32; @@ -125,6 +137,12 @@ mod tests { ) -> f32; pub fn rust_dbg_abi_1(q: Quad) -> Quad; pub fn rust_dbg_abi_2(f: Floats) -> Floats; + pub fn rust_dbg_new_some_u64u64(a: u64, b: u64) -> U8TaggedEnumOptionU64U64; + pub fn rust_dbg_new_none_u64u64() -> U8TaggedEnumOptionU64U64; + pub fn rust_dbg_unpack_option_u64u64(o: U8TaggedEnumOptionU64U64, a: *mut u64, b: *mut u64) -> i32; + pub fn rust_dbg_new_some_u64(some: u64) -> U8TaggedEnumOptionU64; + pub fn rust_dbg_new_none_u64() -> U8TaggedEnumOptionU64; + pub fn rust_dbg_unpack_option_u64(o: U8TaggedEnumOptionU64, v: *mut u64) -> i32; } pub fn cabi_int_widening() { @@ -336,6 +354,59 @@ mod tests { test1(); test2(); } + + pub fn enum_passing_and_return_pair() { + let some_u64u64 = unsafe { rust_dbg_new_some_u64u64(10, 20) }; + if let U8TaggedEnumOptionU64U64::Some(a, b) = some_u64u64 { + assert_eq!(10, a); + assert_eq!(20, b); + } else { + panic!("unexpected none"); + } + + let none_u64u64 = unsafe { rust_dbg_new_none_u64u64() }; + if let U8TaggedEnumOptionU64U64::Some(_,_) = none_u64u64 { + panic!("unexpected some"); + } + + let mut a: u64 = 0; + let mut b: u64 = 0; + let r = unsafe { rust_dbg_unpack_option_u64u64(some_u64u64, &mut a as *mut _, &mut b as *mut _) }; + assert_eq!(1, r); + assert_eq!(10, a); + assert_eq!(20, b); + + let mut a: u64 = 0; + let mut b: u64 = 0; + let r = unsafe { rust_dbg_unpack_option_u64u64(none_u64u64, &mut a as *mut _, &mut b as *mut _) }; + assert_eq!(0, r); + assert_eq!(0, a); + assert_eq!(0, b); + } + + pub fn enum_passing_and_return() { + let some_u64 = unsafe { rust_dbg_new_some_u64(10) }; + if let U8TaggedEnumOptionU64::Some(v) = some_u64 { + assert_eq!(10, v); + } else { + panic!("unexpected none"); + } + + let none_u64 = unsafe { rust_dbg_new_none_u64() }; + if let U8TaggedEnumOptionU64::Some(_) = none_u64 { + panic!("unexpected some"); + } + + let mut target: u64 = 0; + let r = unsafe { rust_dbg_unpack_option_u64(some_u64, &mut target as *mut _) }; + assert_eq!(1, r); + assert_eq!(10, target); + + let mut target: u64 = 0; + let r = unsafe { rust_dbg_unpack_option_u64(none_u64, &mut target as *mut _) }; + assert_eq!(0, r); + assert_eq!(0, target); + } } #[cfg(target_arch = "x86_64")] @@ -359,6 +430,8 @@ fn main() { issue_28676(); issue_62350(); struct_return(); + enum_passing_and_return_pair(); + enum_passing_and_return(); } #[cfg(not(target_arch = "x86_64"))]