diff --git a/rust-version b/rust-version index 88a4ddfba6..f173cc37e8 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -008c21c9779fd1e3632d9fe908b8afc0c421b26c +dca2d1ff00bf96d244b1bb9a2117a92ec50ac71d diff --git a/tests/fail/function_pointers/abi_mismatch_array_vs_struct.rs b/tests/fail/function_pointers/abi_mismatch_array_vs_struct.rs new file mode 100644 index 0000000000..415e91b250 --- /dev/null +++ b/tests/fail/function_pointers/abi_mismatch_array_vs_struct.rs @@ -0,0 +1,16 @@ +#![feature(portable_simd)] + +// Some targets treat arrays and structs very differently. We would probably catch that on those +// targets since we check the `PassMode`; here we ensure that we catch it on *all* targets +// (in particular, on x86-64 the pass mode is `Indirect` for both of these). +struct S(i32, i32, i32, i32); +type A = [i32; 4]; + +fn main() { + fn f(_: S) {} + + // These two types have the same size but are still not compatible. + let g = unsafe { std::mem::transmute::(f) }; + + g(Default::default()) //~ ERROR: calling a function with argument of type S passing data of type [i32; 4] +} diff --git a/tests/fail/function_pointers/abi_mismatch_array_vs_struct.stderr b/tests/fail/function_pointers/abi_mismatch_array_vs_struct.stderr new file mode 100644 index 0000000000..50d4228c11 --- /dev/null +++ b/tests/fail/function_pointers/abi_mismatch_array_vs_struct.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: calling a function with argument of type S passing data of type [i32; 4] + --> $DIR/abi_mismatch_array_vs_struct.rs:LL:CC + | +LL | g(Default::default()) + | ^^^^^^^^^^^^^^^^^^^^^ calling a function with argument of type S passing data of type [i32; 4] + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at $DIR/abi_mismatch_array_vs_struct.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/fail/function_pointers/abi_mismatch_int_vs_float.rs b/tests/fail/function_pointers/abi_mismatch_int_vs_float.rs new file mode 100644 index 0000000000..a1fda329e8 --- /dev/null +++ b/tests/fail/function_pointers/abi_mismatch_int_vs_float.rs @@ -0,0 +1,7 @@ +fn main() { + fn f(_: f32) {} + + let g = unsafe { std::mem::transmute::(f) }; + + g(42) //~ ERROR: calling a function with argument of type f32 passing data of type i32 +} diff --git a/tests/fail/function_pointers/abi_mismatch_int_vs_float.stderr b/tests/fail/function_pointers/abi_mismatch_int_vs_float.stderr new file mode 100644 index 0000000000..a53126c733 --- /dev/null +++ b/tests/fail/function_pointers/abi_mismatch_int_vs_float.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: calling a function with argument of type f32 passing data of type i32 + --> $DIR/abi_mismatch_int_vs_float.rs:LL:CC + | +LL | g(42) + | ^^^^^ calling a function with argument of type f32 passing data of type i32 + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at $DIR/abi_mismatch_int_vs_float.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/fail/function_pointers/cast_fn_ptr4.rs b/tests/fail/function_pointers/abi_mismatch_raw_pointer.rs similarity index 100% rename from tests/fail/function_pointers/cast_fn_ptr4.rs rename to tests/fail/function_pointers/abi_mismatch_raw_pointer.rs diff --git a/tests/fail/function_pointers/cast_fn_ptr4.stderr b/tests/fail/function_pointers/abi_mismatch_raw_pointer.stderr similarity index 85% rename from tests/fail/function_pointers/cast_fn_ptr4.stderr rename to tests/fail/function_pointers/abi_mismatch_raw_pointer.stderr index 610425658f..6eacfeece1 100644 --- a/tests/fail/function_pointers/cast_fn_ptr4.stderr +++ b/tests/fail/function_pointers/abi_mismatch_raw_pointer.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: calling a function with argument of type *const [i32] passing data of type *const i32 - --> $DIR/cast_fn_ptr4.rs:LL:CC + --> $DIR/abi_mismatch_raw_pointer.rs:LL:CC | LL | g(&42 as *const i32) | ^^^^^^^^^^^^^^^^^^^^ calling a function with argument of type *const [i32] passing data of type *const i32 @@ -7,7 +7,7 @@ LL | g(&42 as *const i32) = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/cast_fn_ptr4.rs:LL:CC + = note: inside `main` at $DIR/abi_mismatch_raw_pointer.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/cast_fn_ptr5.rs b/tests/fail/function_pointers/abi_mismatch_return_type.rs similarity index 100% rename from tests/fail/function_pointers/cast_fn_ptr5.rs rename to tests/fail/function_pointers/abi_mismatch_return_type.rs diff --git a/tests/fail/function_pointers/cast_fn_ptr5.stderr b/tests/fail/function_pointers/abi_mismatch_return_type.stderr similarity index 84% rename from tests/fail/function_pointers/cast_fn_ptr5.stderr rename to tests/fail/function_pointers/abi_mismatch_return_type.stderr index c4e08b5843..eedc123577 100644 --- a/tests/fail/function_pointers/cast_fn_ptr5.stderr +++ b/tests/fail/function_pointers/abi_mismatch_return_type.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: calling a function with return type u32 passing return place of type () - --> $DIR/cast_fn_ptr5.rs:LL:CC + --> $DIR/abi_mismatch_return_type.rs:LL:CC | LL | g() | ^^^ calling a function with return type u32 passing return place of type () @@ -7,7 +7,7 @@ LL | g() = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/cast_fn_ptr5.rs:LL:CC + = note: inside `main` at $DIR/abi_mismatch_return_type.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/cast_fn_ptr2.rs b/tests/fail/function_pointers/abi_mismatch_simple.rs similarity index 100% rename from tests/fail/function_pointers/cast_fn_ptr2.rs rename to tests/fail/function_pointers/abi_mismatch_simple.rs diff --git a/tests/fail/function_pointers/cast_fn_ptr2.stderr b/tests/fail/function_pointers/abi_mismatch_simple.stderr similarity index 85% rename from tests/fail/function_pointers/cast_fn_ptr2.stderr rename to tests/fail/function_pointers/abi_mismatch_simple.stderr index 086712e0d1..bc500a90b7 100644 --- a/tests/fail/function_pointers/cast_fn_ptr2.stderr +++ b/tests/fail/function_pointers/abi_mismatch_simple.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: calling a function with argument of type (i32, i32) passing data of type i32 - --> $DIR/cast_fn_ptr2.rs:LL:CC + --> $DIR/abi_mismatch_simple.rs:LL:CC | LL | g(42) | ^^^^^ calling a function with argument of type (i32, i32) passing data of type i32 @@ -7,7 +7,7 @@ LL | g(42) = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/cast_fn_ptr2.rs:LL:CC + = note: inside `main` at $DIR/abi_mismatch_simple.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/cast_fn_ptr3.rs b/tests/fail/function_pointers/abi_mismatch_too_few_args.rs similarity index 100% rename from tests/fail/function_pointers/cast_fn_ptr3.rs rename to tests/fail/function_pointers/abi_mismatch_too_few_args.rs diff --git a/tests/fail/function_pointers/cast_fn_ptr3.stderr b/tests/fail/function_pointers/abi_mismatch_too_few_args.stderr similarity index 83% rename from tests/fail/function_pointers/cast_fn_ptr3.stderr rename to tests/fail/function_pointers/abi_mismatch_too_few_args.stderr index 55fd7d6072..558d83bcfd 100644 --- a/tests/fail/function_pointers/cast_fn_ptr3.stderr +++ b/tests/fail/function_pointers/abi_mismatch_too_few_args.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: calling a function with fewer arguments than it requires - --> $DIR/cast_fn_ptr3.rs:LL:CC + --> $DIR/abi_mismatch_too_few_args.rs:LL:CC | LL | g() | ^^^ calling a function with fewer arguments than it requires @@ -7,7 +7,7 @@ LL | g() = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/cast_fn_ptr3.rs:LL:CC + = note: inside `main` at $DIR/abi_mismatch_too_few_args.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/cast_fn_ptr1.rs b/tests/fail/function_pointers/abi_mismatch_too_many_args.rs similarity index 100% rename from tests/fail/function_pointers/cast_fn_ptr1.rs rename to tests/fail/function_pointers/abi_mismatch_too_many_args.rs diff --git a/tests/fail/function_pointers/cast_fn_ptr1.stderr b/tests/fail/function_pointers/abi_mismatch_too_many_args.stderr similarity index 83% rename from tests/fail/function_pointers/cast_fn_ptr1.stderr rename to tests/fail/function_pointers/abi_mismatch_too_many_args.stderr index bb2a263795..dc12073952 100644 --- a/tests/fail/function_pointers/cast_fn_ptr1.stderr +++ b/tests/fail/function_pointers/abi_mismatch_too_many_args.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: calling a function with more arguments than it expected - --> $DIR/cast_fn_ptr1.rs:LL:CC + --> $DIR/abi_mismatch_too_many_args.rs:LL:CC | LL | g(42) | ^^^^^ calling a function with more arguments than it expected @@ -7,7 +7,7 @@ LL | g(42) = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: - = note: inside `main` at $DIR/cast_fn_ptr1.rs:LL:CC + = note: inside `main` at $DIR/abi_mismatch_too_many_args.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/abi_mismatch_vector.rs b/tests/fail/function_pointers/abi_mismatch_vector.rs new file mode 100644 index 0000000000..80f357b61b --- /dev/null +++ b/tests/fail/function_pointers/abi_mismatch_vector.rs @@ -0,0 +1,11 @@ +#![feature(portable_simd)] +use std::simd; + +fn main() { + fn f(_: simd::u32x8) {} + + // These two vector types have the same size but are still not compatible. + let g = unsafe { std::mem::transmute::(f) }; + + g(Default::default()) //~ ERROR: calling a function with argument of type std::simd::Simd passing data of type std::simd::Simd +} diff --git a/tests/fail/function_pointers/abi_mismatch_vector.stderr b/tests/fail/function_pointers/abi_mismatch_vector.stderr new file mode 100644 index 0000000000..7dcca1e85b --- /dev/null +++ b/tests/fail/function_pointers/abi_mismatch_vector.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: calling a function with argument of type std::simd::Simd passing data of type std::simd::Simd + --> $DIR/abi_mismatch_vector.rs:LL:CC + | +LL | g(Default::default()) + | ^^^^^^^^^^^^^^^^^^^^^ calling a function with argument of type std::simd::Simd passing data of type std::simd::Simd + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `main` at $DIR/abi_mismatch_vector.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/pass/function_calls/abi_compat.rs b/tests/pass/function_calls/abi_compat.rs index e586700b0e..dc1e1f0ba8 100644 --- a/tests/pass/function_calls/abi_compat.rs +++ b/tests/pass/function_calls/abi_compat.rs @@ -1,29 +1,91 @@ +#![feature(portable_simd)] use std::mem; use std::num; +use std::simd; -fn test_abi_compat(t: T, u: U) { +#[derive(Copy, Clone)] +struct Zst; + +fn test_abi_compat(t: T, u: U) { fn id(x: T) -> T { x } + extern "C" fn id_c(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: T) { + #[repr(transparent)] + #[derive(Copy, Clone)] + struct Wrapper1(T); + #[repr(transparent)] + #[derive(Copy, Clone)] + struct Wrapper2(T, ()); + #[repr(transparent)] + #[derive(Copy, Clone)] + struct Wrapper2a((), T); + #[repr(transparent)] + #[derive(Copy, Clone)] + struct Wrapper3(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(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 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); - // Note that `bool` and `u8` are *not* compatible! + 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)); + // 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]); + } }