| // Tests that C++ exceptions can unwind through Rust code run destructors and | |
| // are caught by catch_unwind. Also tests that Rust panics can unwind through | |
| // C++ code. | |
| use std::panic::{AssertUnwindSafe, catch_unwind}; | |
| struct DropCheck<'a>(&'a mut bool); | |
| impl<'a> Drop for DropCheck<'a> { | |
| fn drop(&mut self) { | |
| println!("DropCheck::drop"); | |
| *self.0 = true; | |
| } | |
| } | |
| extern "C" { | |
| fn test_cxx_exception(); | |
| } | |
| extern "C-unwind" { | |
| fn cxx_catch_callback(cb: extern "C-unwind" fn(), ok: *mut bool); | |
| } | |
| #[no_mangle] | |
| extern "C-unwind" fn rust_catch_callback(cb: extern "C-unwind" fn(), rust_ok: &mut bool) { | |
| let _drop = DropCheck(rust_ok); | |
| cb(); | |
| unreachable!("should have unwound instead of returned"); | |
| } | |
| fn test_rust_panic() { | |
| extern "C-unwind" fn callback() { | |
| println!("throwing rust panic"); | |
| panic!(1234i32); | |
| } | |
| let mut dropped = false; | |
| let mut cxx_ok = false; | |
| let caught_unwind = catch_unwind(AssertUnwindSafe(|| { | |
| let _drop = DropCheck(&mut dropped); | |
| unsafe { | |
| cxx_catch_callback(callback, &mut cxx_ok); | |
| } | |
| unreachable!("should have unwound instead of returned"); | |
| })); | |
| println!("caught rust panic"); | |
| assert!(dropped); | |
| assert!(caught_unwind.is_err()); | |
| let panic_obj = caught_unwind.unwrap_err(); | |
| let panic_int = *panic_obj.downcast_ref::<i32>().unwrap(); | |
| assert_eq!(panic_int, 1234); | |
| assert!(cxx_ok); | |
| } | |
| fn main() { | |
| unsafe { test_cxx_exception() }; | |
| test_rust_panic(); | |
| } |