|
1 | 1 | #![feature(portable_simd)]
|
2 |
| -use std::num; |
3 | 2 | use std::mem;
|
| 3 | +use std::num; |
4 | 4 | use std::simd;
|
5 | 5 |
|
6 |
| -fn test_abi_compat<T, U>(t: T, u: U) { |
7 |
| - fn id<T>(x: T) -> T { x } |
8 |
| - |
| 6 | +#[derive(Copy, Clone)] |
| 7 | +struct Zst; |
| 8 | + |
| 9 | +fn test_abi_compat<T: Copy, U: Copy>(t: T, u: U) { |
| 10 | + fn id<T>(x: T) -> T { |
| 11 | + x |
| 12 | + } |
| 13 | + extern "C" fn id_c<T>(x: T) -> T { |
| 14 | + x |
| 15 | + } |
| 16 | + |
9 | 17 | // This checks ABI compatibility both for arguments and return values,
|
10 | 18 | // in both directions.
|
11 | 19 | let f: fn(T) -> T = id;
|
12 | 20 | let f: fn(U) -> U = unsafe { std::mem::transmute(f) };
|
13 |
| - drop(f(u)); |
14 |
| - |
| 21 | + let _val = f(u); |
15 | 22 | let f: fn(U) -> U = id;
|
16 | 23 | let f: fn(T) -> T = unsafe { std::mem::transmute(f) };
|
17 |
| - drop(f(t)); |
| 24 | + let _val = f(t); |
| 25 | + |
| 26 | + // And then we do the same for `extern "C"`. |
| 27 | + let f: extern "C" fn(T) -> T = id_c; |
| 28 | + let f: extern "C" fn(U) -> U = unsafe { std::mem::transmute(f) }; |
| 29 | + let _val = f(u); |
| 30 | + let f: extern "C" fn(U) -> U = id_c; |
| 31 | + let f: extern "C" fn(T) -> T = unsafe { std::mem::transmute(f) }; |
| 32 | + let _val = f(t); |
18 | 33 | }
|
19 | 34 |
|
20 | 35 | /// Ensure that `T` is compatible with various repr(transparent) wrappers around `T`.
|
21 | 36 | fn test_abi_newtype<T: Copy>(t: T) {
|
22 | 37 | #[repr(transparent)]
|
| 38 | + #[derive(Copy, Clone)] |
23 | 39 | struct Wrapper1<T>(T);
|
24 | 40 | #[repr(transparent)]
|
| 41 | + #[derive(Copy, Clone)] |
25 | 42 | struct Wrapper2<T>(T, ());
|
26 | 43 | #[repr(transparent)]
|
| 44 | + #[derive(Copy, Clone)] |
27 | 45 | struct Wrapper2a<T>((), T);
|
28 | 46 | #[repr(transparent)]
|
29 |
| - struct Wrapper3<T>(T, [u8; 0]); |
| 47 | + #[derive(Copy, Clone)] |
| 48 | + struct Wrapper3<T>(Zst, T, [u8; 0]); |
30 | 49 |
|
31 | 50 | test_abi_compat(t, Wrapper1(t));
|
32 | 51 | test_abi_compat(t, Wrapper2(t, ()));
|
33 | 52 | test_abi_compat(t, Wrapper2a((), t));
|
34 |
| - test_abi_compat(t, Wrapper3(t, [])); |
| 53 | + test_abi_compat(t, Wrapper3(Zst, t, [])); |
| 54 | + test_abi_compat(t, mem::MaybeUninit::new(t)); // MaybeUninit is `repr(transparent)` |
35 | 55 | }
|
36 | 56 |
|
37 | 57 | fn main() {
|
| 58 | + // Here we check: |
| 59 | + // - unsigned vs signed integer is allowed |
| 60 | + // - u32/i32 vs char is allowed |
| 61 | + // - u32 vs NonZeroU32/Option<NonZeroU32> is allowed |
| 62 | + // - reference vs raw pointer is allowed |
| 63 | + // - references to things of the same size and alignment are allowed |
| 64 | + // These are very basic tests that should work on all ABIs. However it is not clear that any of |
| 65 | + // these would be stably guaranteed. Code that relies on this is equivalent to code that relies |
| 66 | + // on the layout of `repr(Rust)` types. They are also fragile: the same mismatches in the fields |
| 67 | + // of a struct (even with `repr(C)`) will not always be accepted by Miri. |
| 68 | + test_abi_compat(0u32, 0i32); |
| 69 | + test_abi_compat(simd::u32x8::splat(1), simd::i32x8::splat(1)); |
38 | 70 | test_abi_compat(0u32, 'x');
|
39 |
| - test_abi_compat(&0u32, &([true; 4], [0u32; 0])); |
40 |
| - test_abi_compat(0u32, mem::MaybeUninit::new(0u32)); |
| 71 | + test_abi_compat(0i32, 'x'); |
41 | 72 | test_abi_compat(42u32, num::NonZeroU32::new(1).unwrap());
|
42 | 73 | test_abi_compat(0u32, Some(num::NonZeroU32::new(1).unwrap()));
|
43 |
| - test_abi_compat(0u32, 0i32); |
44 |
| - test_abi_compat(simd::u32x8::splat(1), simd::i32x8::splat(1)); |
| 74 | + test_abi_compat(&0u32, &0u32 as *const u32); |
| 75 | + test_abi_compat(&0u32, &([true; 4], [0u32; 0])); |
45 | 76 | // Note that `bool` and `u8` are *not* compatible, at least on x86-64!
|
46 | 77 | // One of them has `arg_ext: Zext`, the other does not.
|
47 | 78 |
|
| 79 | + // These must work for *any* type, since we guarantee that `repr(transparent)` is ABI-compatible |
| 80 | + // with the wrapped field. |
| 81 | + test_abi_newtype(()); |
| 82 | + // FIXME: this still fails! test_abi_newtype(Zst); |
48 | 83 | test_abi_newtype(0u32);
|
49 | 84 | test_abi_newtype(0f32);
|
50 | 85 | test_abi_newtype((0u32, 1u32, 2u32));
|
51 |
| - test_abi_newtype([0u32, 1u32, 2u32]); |
52 |
| - test_abi_newtype([0i32; 0]); |
| 86 | + // FIXME: skipping the array tests on mips64 due to https://github.com/rust-lang/rust/issues/115404 |
| 87 | + if !cfg!(target_arch = "mips64") { |
| 88 | + test_abi_newtype([0u32, 1u32, 2u32]); |
| 89 | + test_abi_newtype([0i32; 0]); |
| 90 | + } |
53 | 91 | }
|
0 commit comments