// 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::().unwrap(); assert_eq!(panic_int, 1234); assert!(cxx_ok); } fn main() { unsafe { test_cxx_exception() }; test_rust_panic(); }