diff options
| author | Maybe Waffle <waffle.lapkin@gmail.com> | 2024-06-17 15:37:33 +0000 |
|---|---|---|
| committer | Maybe Lapkin <waffle.lapkin@gmail.com> | 2024-07-07 18:16:38 +0200 |
| commit | 6d4995f4e6d3f4fe6ac54943a5b01c3cf752dd5d (patch) | |
| tree | 40c8b84297114b93625f9e5beed41ec39aa4aa40 | |
| parent | cda25e56c8d4f810d19034ebf5d0e4fdb155a264 (diff) | |
| download | rust-6d4995f4e6d3f4fe6ac54943a5b01c3cf752dd5d.tar.gz rust-6d4995f4e6d3f4fe6ac54943a5b01c3cf752dd5d.zip | |
add miri tests and a fixme
6 files changed, 112 insertions, 0 deletions
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index a8d18405b6e..9f4ca93a3e8 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -992,6 +992,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { bug!("can't tailcall as root"); }; + // FIXME(explicit_tail_calls): + // we should check if both caller&callee can/n't unwind, + // see <https://github.com/rust-lang/rust/pull/113128#issuecomment-1614979803> + self.eval_fn_call( fn_val, (caller_abi, caller_fn_abi), diff --git a/src/tools/miri/tests/fail/tail_calls/cc-mismatch.rs b/src/tools/miri/tests/fail/tail_calls/cc-mismatch.rs new file mode 100644 index 00000000000..5f00dbf2573 --- /dev/null +++ b/src/tools/miri/tests/fail/tail_calls/cc-mismatch.rs @@ -0,0 +1,10 @@ +//@error-in-other-file: Undefined Behavior: calling a function with calling convention C using calling convention Rust +#![feature(explicit_tail_calls)] +#![allow(incomplete_features)] + +fn main() { + let f = unsafe { std::mem::transmute::<extern "C" fn(), fn()>(f) }; + become f(); +} + +extern "C" fn f() {} diff --git a/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr b/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr new file mode 100644 index 00000000000..708972e6eff --- /dev/null +++ b/src/tools/miri/tests/fail/tail_calls/cc-mismatch.stderr @@ -0,0 +1,25 @@ +error: Undefined Behavior: calling a function with calling convention C using calling convention Rust + --> RUSTLIB/core/src/ops/function.rs:LL:CC + | +LL | extern "rust-call" fn call_once(self, args: Args) -> Self::Output; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling a function with calling convention C using calling convention Rust + | + = 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 `<fn() as std::ops::FnOnce<()>>::call_once - shim(fn())` at RUSTLIB/core/src/ops/function.rs:LL:CC + = note: inside `std::sys_common::backtrace::__rust_begin_short_backtrace::<fn(), ()>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/rt.rs:LL:CC + = note: inside `std::ops::function::impls::<impl std::ops::FnOnce<()> for &dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe>::call_once` at RUSTLIB/core/src/ops/function.rs:LL:CC + = note: inside `std::panicking::r#try::do_call::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::panicking::r#try::<i32, &dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe>` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::panic::catch_unwind::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>` at RUSTLIB/std/src/panic.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/rt.rs:LL:CC + = note: inside `std::panicking::r#try::do_call::<{closure@std::rt::lang_start_internal::{closure#2}}, isize>` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::panicking::r#try::<isize, {closure@std::rt::lang_start_internal::{closure#2}}>` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::panic::catch_unwind::<{closure@std::rt::lang_start_internal::{closure#2}}, isize>` at RUSTLIB/std/src/panic.rs:LL:CC + = note: inside `std::rt::lang_start_internal` at RUSTLIB/std/src/rt.rs:LL:CC + = note: inside `std::rt::lang_start::<()>` at RUSTLIB/std/src/rt.rs:LL:CC + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.rs b/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.rs new file mode 100644 index 00000000000..3264a74d159 --- /dev/null +++ b/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.rs @@ -0,0 +1,17 @@ +#![feature(explicit_tail_calls)] +#![allow(incomplete_features)] + +fn main() { + // FIXME(explicit_tail_calls): + // the error should point to `become f(x)`, + // but tail calls mess up the backtrace it seems like... + f(0); + //~^ error: Undefined Behavior: calling a function with argument of type i32 passing data of type u32 +} + +fn f(x: u32) { + let g = unsafe { std::mem::transmute::<fn(i32), fn(u32)>(g) }; + become g(x); +} + +fn g(_: i32) {} diff --git a/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.stderr b/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.stderr new file mode 100644 index 00000000000..2ecc5674c65 --- /dev/null +++ b/src/tools/miri/tests/fail/tail_calls/signature-mismatch-arg.stderr @@ -0,0 +1,17 @@ +error: Undefined Behavior: calling a function with argument of type i32 passing data of type u32 + --> $DIR/signature-mismatch-arg.rs:LL:CC + | +LL | f(0); + | ^^^^ calling a function with argument of type i32 passing data of type u32 + | + = 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 + = help: this means these two types are not *guaranteed* to be ABI-compatible across all targets + = help: if you think this code should be accepted anyway, please report an issue + = note: BACKTRACE: + = note: inside `main` at $DIR/signature-mismatch-arg.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/pass/tail_call.rs b/src/tools/miri/tests/pass/tail_call.rs new file mode 100644 index 00000000000..f6200706398 --- /dev/null +++ b/src/tools/miri/tests/pass/tail_call.rs @@ -0,0 +1,39 @@ +#![allow(incomplete_features)] +#![feature(explicit_tail_calls)] + +fn main() { + assert_eq!(factorial(10), 3_628_800); + assert_eq!(mutually_recursive_identity(1000), 1000); +} + +fn factorial(n: u32) -> u32 { + fn factorial_acc(n: u32, acc: u32) -> u32 { + match n { + 0 => acc, + _ => become factorial_acc(n - 1, acc * n), + } + } + + factorial_acc(n, 1) +} + +// this is of course very silly, but we need to demonstrate mutual recursion somehow so... +fn mutually_recursive_identity(x: u32) -> u32 { + fn switch(src: u32, tgt: u32) -> u32 { + match src { + 0 => tgt, + _ if src % 7 == 0 => become advance_with_extra_steps(src, tgt), + _ => become advance(src, tgt), + } + } + + fn advance(src: u32, tgt: u32) -> u32 { + become switch(src - 1, tgt + 1) + } + + fn advance_with_extra_steps(src: u32, tgt: u32) -> u32 { + become advance(src, tgt) + } + + switch(x, 0) +} |
