diff --git a/src/libpanic_unwind/emcc.rs b/src/libpanic_unwind/emcc.rs index fbadf4ac6a0..268bafd2409 100644 --- a/src/libpanic_unwind/emcc.rs +++ b/src/libpanic_unwind/emcc.rs @@ -80,6 +80,7 @@ pub unsafe fn panic(data: Box) -> u32 { extern "C" fn exception_cleanup(ptr: *mut libc::c_void) { unsafe { ptr::drop_in_place(ptr as *mut Exception); + super::__rust_drop_panic(); } } } diff --git a/src/libpanic_unwind/gcc.rs b/src/libpanic_unwind/gcc.rs index 6bec2686533..6e04317d491 100644 --- a/src/libpanic_unwind/gcc.rs +++ b/src/libpanic_unwind/gcc.rs @@ -78,6 +78,7 @@ pub unsafe fn panic(data: Box) -> u32 { ) { unsafe { let _: Box = Box::from_raw(exception as *mut Exception); + super::__rust_drop_panic(); } } } diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs index 9451eefb9a5..6383ae39fb6 100644 --- a/src/libpanic_unwind/lib.rs +++ b/src/libpanic_unwind/lib.rs @@ -61,6 +61,12 @@ cfg_if::cfg_if! { } } +extern "C" { + /// Handler in libstd called when a panic object is dropped outside of + /// `catch_unwind`. + fn __rust_drop_panic() -> !; +} + mod dwarf; // Entry point for catching an exception, implemented using the `try` intrinsic diff --git a/src/libpanic_unwind/seh.rs b/src/libpanic_unwind/seh.rs index f1d0080472a..d9dca2c0f4f 100644 --- a/src/libpanic_unwind/seh.rs +++ b/src/libpanic_unwind/seh.rs @@ -229,6 +229,7 @@ macro_rules! define_cleanup { unsafe extern $abi fn exception_cleanup(e: *mut [u64; 2]) { if (*e)[0] != 0 { cleanup(*e); + super::__rust_drop_panic(); } } #[unwind(allowed)] diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 599ccc809be..43c2965f231 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -55,6 +55,14 @@ extern "C" { fn __rust_start_panic(payload: usize) -> u32; } +/// This function is called by the panic runtime if FFI code catches a Rust +/// panic but doesn't rethrow it. We don't support this case since it messes +/// with our panic count. +#[rustc_std_internal_symbol] +extern "C" fn __rust_drop_panic() -> ! { + rtabort!("Rust panics must be rethrown"); +} + #[derive(Copy, Clone)] enum Hook { Default, diff --git a/src/test/run-make-fulldeps/foreign-exceptions/foo.cpp b/src/test/run-make-fulldeps/foreign-exceptions/foo.cpp index ef5cd74c652..b0fd65f88e7 100644 --- a/src/test/run-make-fulldeps/foreign-exceptions/foo.cpp +++ b/src/test/run-make-fulldeps/foreign-exceptions/foo.cpp @@ -57,21 +57,4 @@ extern "C" { throw; } } - - void swallow_exception(void (*cb)()) { - try { - // Do a rethrow to ensure that the exception is only dropped once. - // This is necessary since we don't support copying exceptions. - try { - cb(); - } catch (...) { - println("rethrowing Rust panic"); - throw; - }; - } catch (rust_panic e) { - assert(false && "shouldn't be able to catch a rust panic"); - } catch (...) { - println("swallowing foreign exception in catch (...)"); - } - } } diff --git a/src/test/run-make-fulldeps/foreign-exceptions/foo.rs b/src/test/run-make-fulldeps/foreign-exceptions/foo.rs index d9818dffc50..9c2045c8c89 100644 --- a/src/test/run-make-fulldeps/foreign-exceptions/foo.rs +++ b/src/test/run-make-fulldeps/foreign-exceptions/foo.rs @@ -19,8 +19,6 @@ impl<'a> Drop for DropCheck<'a> { extern "C" { fn throw_cxx_exception(); - fn swallow_exception(cb: extern "C" fn()); - #[unwind(allowed)] fn cxx_catch_callback(cb: extern "C" fn(), ok: *mut bool); } @@ -61,34 +59,7 @@ fn throw_rust_panic() { assert!(cxx_ok); } -fn check_exception_drop() { - static mut DROP_COUNT: usize = 0; - - struct CountDrop; - impl Drop for CountDrop { - fn drop(&mut self) { - println!("CountDrop::drop"); - unsafe { - DROP_COUNT += 1; - } - } - } - - - #[unwind(allowed)] - extern "C" fn callback() { - println!("throwing rust panic #2"); - panic!(CountDrop); - } - - unsafe { - swallow_exception(callback); - assert_eq!(DROP_COUNT, 1); - } -} - fn main() { unsafe { throw_cxx_exception() }; throw_rust_panic(); - check_exception_drop(); }