diff options
| author | Ralf Jung <post@ralfj.de> | 2023-08-31 11:35:31 +0200 |
|---|---|---|
| committer | Ralf Jung <post@ralfj.de> | 2023-08-31 13:21:55 +0200 |
| commit | c2b0ca75aad47edcc403738c49387284ce55f5bf (patch) | |
| tree | d03e6a16ff0145c8b0928f8d1446ba5cb9b64b69 | |
| parent | 9db09c571fa4cc73278796afc2669533348e27c4 (diff) | |
| download | rust-c2b0ca75aad47edcc403738c49387284ce55f5bf.tar.gz rust-c2b0ca75aad47edcc403738c49387284ce55f5bf.zip | |
more ABI compat tests
| -rw-r--r-- | src/tools/miri/tests/pass/function_calls/abi_compat.rs | 60 |
1 files changed, 48 insertions, 12 deletions
diff --git a/src/tools/miri/tests/pass/function_calls/abi_compat.rs b/src/tools/miri/tests/pass/function_calls/abi_compat.rs index 30ab2d05889..dc1e1f0ba8d 100644 --- a/src/tools/miri/tests/pass/function_calls/abi_compat.rs +++ b/src/tools/miri/tests/pass/function_calls/abi_compat.rs @@ -3,53 +3,89 @@ use std::mem; use std::num; use std::simd; -fn test_abi_compat<T, U>(t: T, u: U) { +#[derive(Copy, Clone)] +struct Zst; + +fn test_abi_compat<T: Copy, U: Copy>(t: T, u: U) { fn id<T>(x: T) -> T { x } + extern "C" fn id_c<T>(x: T) -> T { + x + } // This checks ABI compatibility both for arguments and return values, // in both directions. let f: fn(T) -> T = id; let f: fn(U) -> U = unsafe { std::mem::transmute(f) }; - drop(f(u)); - + let _val = f(u); let f: fn(U) -> U = id; let f: fn(T) -> T = unsafe { std::mem::transmute(f) }; - drop(f(t)); + let _val = f(t); + + // And then we do the same for `extern "C"`. + let f: extern "C" fn(T) -> T = id_c; + let f: extern "C" fn(U) -> U = unsafe { std::mem::transmute(f) }; + let _val = f(u); + let f: extern "C" fn(U) -> U = id_c; + let f: extern "C" fn(T) -> T = unsafe { std::mem::transmute(f) }; + let _val = f(t); } /// Ensure that `T` is compatible with various repr(transparent) wrappers around `T`. fn test_abi_newtype<T: Copy>(t: T) { #[repr(transparent)] + #[derive(Copy, Clone)] struct Wrapper1<T>(T); #[repr(transparent)] + #[derive(Copy, Clone)] struct Wrapper2<T>(T, ()); #[repr(transparent)] + #[derive(Copy, Clone)] struct Wrapper2a<T>((), T); #[repr(transparent)] - struct Wrapper3<T>(T, [u8; 0]); + #[derive(Copy, Clone)] + struct Wrapper3<T>(Zst, T, [u8; 0]); test_abi_compat(t, Wrapper1(t)); test_abi_compat(t, Wrapper2(t, ())); test_abi_compat(t, Wrapper2a((), t)); - test_abi_compat(t, Wrapper3(t, [])); + test_abi_compat(t, Wrapper3(Zst, t, [])); + test_abi_compat(t, mem::MaybeUninit::new(t)); // MaybeUninit is `repr(transparent)` } fn main() { + // Here we check: + // - unsigned vs signed integer is allowed + // - u32/i32 vs char is allowed + // - u32 vs NonZeroU32/Option<NonZeroU32> is allowed + // - reference vs raw pointer is allowed + // - references to things of the same size and alignment are allowed + // These are very basic tests that should work on all ABIs. However it is not clear that any of + // these would be stably guaranteed. Code that relies on this is equivalent to code that relies + // on the layout of `repr(Rust)` types. They are also fragile: the same mismatches in the fields + // of a struct (even with `repr(C)`) will not always be accepted by Miri. + test_abi_compat(0u32, 0i32); + test_abi_compat(simd::u32x8::splat(1), simd::i32x8::splat(1)); test_abi_compat(0u32, 'x'); - test_abi_compat(&0u32, &([true; 4], [0u32; 0])); - test_abi_compat(0u32, mem::MaybeUninit::new(0u32)); + test_abi_compat(0i32, 'x'); test_abi_compat(42u32, num::NonZeroU32::new(1).unwrap()); test_abi_compat(0u32, Some(num::NonZeroU32::new(1).unwrap())); - test_abi_compat(0u32, 0i32); - test_abi_compat(simd::u32x8::splat(1), simd::i32x8::splat(1)); + test_abi_compat(&0u32, &0u32 as *const u32); + test_abi_compat(&0u32, &([true; 4], [0u32; 0])); // Note that `bool` and `u8` are *not* compatible, at least on x86-64! // One of them has `arg_ext: Zext`, the other does not. + // These must work for *any* type, since we guarantee that `repr(transparent)` is ABI-compatible + // with the wrapped field. + test_abi_newtype(()); + // FIXME: this still fails! test_abi_newtype(Zst); test_abi_newtype(0u32); test_abi_newtype(0f32); test_abi_newtype((0u32, 1u32, 2u32)); - test_abi_newtype([0u32, 1u32, 2u32]); - test_abi_newtype([0i32; 0]); + // FIXME: skipping the array tests on mips64 due to https://github.com/rust-lang/rust/issues/115404 + if !cfg!(target_arch = "mips64") { + test_abi_newtype([0u32, 1u32, 2u32]); + test_abi_newtype([0i32; 0]); + } } |
