1 // Tests that C++ exceptions can unwind through Rust code run destructors and 2 // are caught by catch_unwind. Also tests that Rust panics can unwind through 3 // C++ code. 4 5 use std::panic::{catch_unwind, AssertUnwindSafe}; 6 7 struct DropCheck<'a>(&'a mut bool); 8 impl<'a> Drop for DropCheck<'a> { drop(&mut self)9 fn drop(&mut self) { 10 println!("DropCheck::drop"); 11 *self.0 = true; 12 } 13 } 14 15 extern "C" { test_cxx_exception()16 fn test_cxx_exception(); 17 } 18 19 extern "C-unwind" { cxx_catch_callback(cb: extern "C-unwind" fn(), ok: *mut bool)20 fn cxx_catch_callback(cb: extern "C-unwind" fn(), ok: *mut bool); 21 } 22 23 #[no_mangle] rust_catch_callback(cb: extern "C-unwind" fn(), rust_ok: &mut bool)24extern "C-unwind" fn rust_catch_callback(cb: extern "C-unwind" fn(), rust_ok: &mut bool) { 25 let _drop = DropCheck(rust_ok); 26 cb(); 27 unreachable!("should have unwound instead of returned"); 28 } 29 test_rust_panic()30fn test_rust_panic() { 31 extern "C-unwind" fn callback() { 32 println!("throwing rust panic"); 33 panic!(1234i32); 34 } 35 36 let mut dropped = false; 37 let mut cxx_ok = false; 38 let caught_unwind = catch_unwind(AssertUnwindSafe(|| { 39 let _drop = DropCheck(&mut dropped); 40 unsafe { 41 cxx_catch_callback(callback, &mut cxx_ok); 42 } 43 unreachable!("should have unwound instead of returned"); 44 })); 45 println!("caught rust panic"); 46 assert!(dropped); 47 assert!(caught_unwind.is_err()); 48 let panic_obj = caught_unwind.unwrap_err(); 49 let panic_int = *panic_obj.downcast_ref::<i32>().unwrap(); 50 assert_eq!(panic_int, 1234); 51 assert!(cxx_ok); 52 } 53 main()54fn main() { 55 unsafe { test_cxx_exception() }; 56 test_rust_panic(); 57 } 58