From 7a46a0b58c20df126eb07aac5b0fcd6e07b6ec3e Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Thu, 26 Dec 2019 10:02:21 -0500 Subject: [PATCH 1/9] Inline catching panics into std::catch_unwind This allows LLVM to inline the happy path, such that catching unwinding is zero-cost when no panic occurs. This also allows us to match the code generated by C++ try/catch. --- src/libpanic_abort/lib.rs | 13 ++----- src/libpanic_unwind/dummy.rs | 4 +- src/libpanic_unwind/emcc.rs | 4 +- src/libpanic_unwind/gcc.rs | 5 +-- src/libpanic_unwind/hermit.rs | 4 +- src/libpanic_unwind/lib.rs | 33 ++++------------ src/libpanic_unwind/seh.rs | 4 +- src/libstd/panicking.rs | 71 ++++++++++++++++++++++------------- 8 files changed, 61 insertions(+), 77 deletions(-) diff --git a/src/libpanic_abort/lib.rs b/src/libpanic_abort/lib.rs index db7c250e21157..ebc57860b9d4a 100644 --- a/src/libpanic_abort/lib.rs +++ b/src/libpanic_abort/lib.rs @@ -17,18 +17,11 @@ #![feature(panic_runtime)] #![feature(staged_api)] #![feature(rustc_attrs)] +#![feature(raw)] -// Rust's "try" function, but if we're aborting on panics we just call the -// function as there's nothing else we need to do here. #[rustc_std_internal_symbol] -pub unsafe extern "C" fn __rust_maybe_catch_panic( - f: fn(*mut u8), - data: *mut u8, - _data_ptr: *mut usize, - _vtable_ptr: *mut usize, -) -> u32 { - f(data); - 0 +pub unsafe extern "C" fn __rust_cleanup(_: *mut u8) -> core::raw::TraitObject { + unreachable!() } // "Leak" the payload and shim to the relevant abort on the platform in diff --git a/src/libpanic_unwind/dummy.rs b/src/libpanic_unwind/dummy.rs index 8675632638712..30593d3b88af9 100644 --- a/src/libpanic_unwind/dummy.rs +++ b/src/libpanic_unwind/dummy.rs @@ -6,9 +6,7 @@ use alloc::boxed::Box; use core::any::Any; use core::intrinsics; -pub fn payload() -> *mut u8 { - core::ptr::null_mut() -} +pub type Payload = *mut u8; pub unsafe fn cleanup(_ptr: *mut u8) -> Box { intrinsics::abort() diff --git a/src/libpanic_unwind/emcc.rs b/src/libpanic_unwind/emcc.rs index 2098404ee1b9d..2859067c098b3 100644 --- a/src/libpanic_unwind/emcc.rs +++ b/src/libpanic_unwind/emcc.rs @@ -48,9 +48,7 @@ static EXCEPTION_TYPE_INFO: TypeInfo = TypeInfo { name: b"rust_panic\0".as_ptr(), }; -pub fn payload() -> *mut u8 { - ptr::null_mut() -} +pub type Payload = *mut u8; pub unsafe fn cleanup(ptr: *mut u8) -> Box { assert!(!ptr.is_null()); diff --git a/src/libpanic_unwind/gcc.rs b/src/libpanic_unwind/gcc.rs index e5e8e805b6e89..e09ced175051f 100644 --- a/src/libpanic_unwind/gcc.rs +++ b/src/libpanic_unwind/gcc.rs @@ -48,7 +48,6 @@ use alloc::boxed::Box; use core::any::Any; -use core::ptr; use crate::dwarf::eh::{self, EHAction, EHContext}; use libc::{c_int, uintptr_t}; @@ -82,9 +81,7 @@ pub unsafe fn panic(data: Box) -> u32 { } } -pub fn payload() -> *mut u8 { - ptr::null_mut() -} +pub type Payload = *mut u8; pub unsafe fn cleanup(ptr: *mut u8) -> Box { let my_ep = ptr as *mut Exception; diff --git a/src/libpanic_unwind/hermit.rs b/src/libpanic_unwind/hermit.rs index 2f53df2861d44..8ffb4bcd3df23 100644 --- a/src/libpanic_unwind/hermit.rs +++ b/src/libpanic_unwind/hermit.rs @@ -6,9 +6,7 @@ use alloc::boxed::Box; use core::any::Any; use core::ptr; -pub fn payload() -> *mut u8 { - ptr::null_mut() -} +pub type Payload = *mut u8; pub unsafe fn cleanup(_ptr: *mut u8) -> Box { extern "C" { diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs index e721162edc067..7481ce65d6337 100644 --- a/src/libpanic_unwind/lib.rs +++ b/src/libpanic_unwind/lib.rs @@ -22,19 +22,19 @@ #![feature(libc)] #![feature(nll)] #![feature(panic_unwind)] -#![feature(raw)] #![feature(staged_api)] #![feature(std_internals)] #![feature(unwind_attributes)] +#![feature(rustc_attrs)] +#![feature(raw)] #![panic_runtime] #![feature(panic_runtime)] use alloc::boxed::Box; -use core::intrinsics; -use core::mem; use core::panic::BoxMeUp; -use core::raw; +// If adding to this list, you should also look at libstd::panicking's identical +// list of Payload types and likely add to there as well. cfg_if::cfg_if! { if #[cfg(target_os = "emscripten")] { #[path = "emcc.rs"] @@ -62,28 +62,11 @@ cfg_if::cfg_if! { mod dwarf; -// Entry point for catching an exception, implemented using the `try` intrinsic -// in the compiler. -// -// The interaction between the `payload` function and the compiler is pretty -// hairy and tightly coupled, for more information see the compiler's -// implementation of this. #[no_mangle] -pub unsafe extern "C" fn __rust_maybe_catch_panic( - f: fn(*mut u8), - data: *mut u8, - data_ptr: *mut usize, - vtable_ptr: *mut usize, -) -> u32 { - let mut payload = imp::payload(); - if intrinsics::r#try(f, data, &mut payload as *mut _ as *mut _) == 0 { - 0 - } else { - let obj = mem::transmute::<_, raw::TraitObject>(imp::cleanup(payload)); - *data_ptr = obj.data as usize; - *vtable_ptr = obj.vtable as usize; - 1 - } +pub unsafe extern "C" fn __rust_panic_cleanup(payload: *mut u8) -> core::raw::TraitObject { + let payload = payload as *mut imp::Payload; + let payload = *(payload); + core::mem::transmute(imp::cleanup(payload)) } // Entry point for raising an exception, just delegates to the platform-specific diff --git a/src/libpanic_unwind/seh.rs b/src/libpanic_unwind/seh.rs index 9a28c47ba9458..3fba52eeb285f 100644 --- a/src/libpanic_unwind/seh.rs +++ b/src/libpanic_unwind/seh.rs @@ -264,9 +264,7 @@ pub unsafe fn panic(data: Box) -> u32 { _CxxThrowException(throw_ptr, &mut THROW_INFO as *mut _ as *mut _); } -pub fn payload() -> [u64; 2] { - [0; 2] -} +pub type Payload = [u64; 2]; pub unsafe fn cleanup(payload: [u64; 2]) -> Box { mem::transmute(raw::TraitObject { data: payload[0] as *mut _, vtable: payload[1] as *mut _ }) diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 43230d7a2c7af..c9639f999ef10 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -12,9 +12,8 @@ use core::panic::{BoxMeUp, Location, PanicInfo}; use crate::any::Any; use crate::fmt; use crate::intrinsics; -use crate::mem::{self, ManuallyDrop}; +use crate::mem::{self, ManuallyDrop, MaybeUninit}; use crate::process; -use crate::raw; use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sys::stdio::panic_output; use crate::sys_common::backtrace::{self, RustBacktrace}; @@ -29,6 +28,31 @@ use crate::io::set_panic; #[cfg(test)] use realstd::io::set_panic; +// This must be kept in sync with the implementations in libpanic_unwind. +// +// This is *not* checked in anyway; the compiler does not allow us to use a +// type/macro/anything from panic_unwind, since we're then linking in the +// panic_unwind runtime even during -Cpanic=abort. +// +// Essentially this must be the type of `imp::Payload` in libpanic_unwind. +cfg_if::cfg_if! { + if #[cfg(not(feature = "panic_unwind"))] { + type Payload = (); + } else if #[cfg(target_os = "emscripten")] { + type Payload = *mut u8; + } else if #[cfg(target_arch = "wasm32")] { + type Payload = *mut u8; + } else if #[cfg(target_os = "hermit")] { + type Payload = *mut u8; + } else if #[cfg(all(target_env = "msvc", target_arch = "aarch64"))] { + type Payload = *mut u8; + } else if #[cfg(target_env = "msvc")] { + type Payload = [u64; 2]; + } else { + type Payload = *mut u8; + } +} + // Binary interface to the panic runtime that the standard library depends on. // // The standard library is tagged with `#![needs_panic_runtime]` (introduced in @@ -41,12 +65,10 @@ use realstd::io::set_panic; // hook up these functions, but it is not this day! #[allow(improper_ctypes)] extern "C" { - fn __rust_maybe_catch_panic( - f: fn(*mut u8), - data: *mut u8, - data_ptr: *mut usize, - vtable_ptr: *mut usize, - ) -> u32; + /// The payload ptr here is actually the same as the payload ptr for the try + /// intrinsic (i.e., is really `*mut [u64; 2]` or `*mut *mut u8`). + #[unwind(allowed)] + fn __rust_panic_cleanup(payload: *mut u8) -> core::raw::TraitObject; /// `payload` is actually a `*mut &mut dyn BoxMeUp` but that would cause FFI warnings. /// It cannot be `Box` because the other end of this call does not depend @@ -241,9 +263,9 @@ pub unsafe fn r#try R>(f: F) -> Result> } // We do some sketchy operations with ownership here for the sake of - // performance. We can only pass pointers down to - // `__rust_maybe_catch_panic` (can't pass objects by value), so we do all - // the ownership tracking here manually using a union. + // performance. We can only pass pointers down to `do_call` (can't pass + // objects by value), so we do all the ownership tracking here manually + // using a union. // // We go through a transition where: // @@ -254,7 +276,7 @@ pub unsafe fn r#try R>(f: F) -> Result> // * If the closure successfully returns, we write the return value into the // data's return slot. Note that `ptr::write` is used as it's overwriting // uninitialized data. - // * Finally, when we come back out of the `__rust_maybe_catch_panic` we're + // * Finally, when we come back out of the `try` intrinsic we're // in one of two states: // // 1. The closure didn't panic, in which case the return value was @@ -265,28 +287,25 @@ pub unsafe fn r#try R>(f: F) -> Result> // // Once we stack all that together we should have the "most efficient' // method of calling a catch panic whilst juggling ownership. - let mut any_data = 0; - let mut any_vtable = 0; let mut data = Data { f: ManuallyDrop::new(f) }; - let r = __rust_maybe_catch_panic( - do_call::, - &mut data as *mut _ as *mut u8, - &mut any_data, - &mut any_vtable, - ); + let mut payload: MaybeUninit = MaybeUninit::uninit(); - return if r == 0 { + let data_ptr = &mut data as *mut _ as *mut u8; + let payload_ptr = payload.as_mut_ptr() as *mut _; + return if intrinsics::r#try(do_call::, data_ptr, payload_ptr) == 0 { debug_assert!(update_panic_count(0) == 0); Ok(ManuallyDrop::into_inner(data.r)) } else { + Err(cleanup(payload.assume_init())) + }; + + unsafe fn cleanup(mut payload: Payload) -> Box { + let obj = crate::mem::transmute(__rust_panic_cleanup(&mut payload as *mut _ as *mut u8)); update_panic_count(-1); debug_assert!(update_panic_count(0) == 0); - Err(mem::transmute(raw::TraitObject { - data: any_data as *mut _, - vtable: any_vtable as *mut _, - })) - }; + obj + } fn do_call R, R>(data: *mut u8) { unsafe { From e177b9129fb6ca50730de1b52489a39c791748bb Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Thu, 26 Dec 2019 10:03:41 -0500 Subject: [PATCH 2/9] Avoid over-aligning the return value in the -Cpanic=abort case --- src/librustc_codegen_llvm/intrinsic.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index abb17b3b0f116..a18ea051e5d2d 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -858,8 +858,10 @@ fn try_intrinsic( ) { if bx.sess().no_landing_pads() { bx.call(func, &[data], None); - let ptr_align = bx.tcx().data_layout.pointer_align.abi; - bx.store(bx.const_null(bx.type_i8p()), dest, ptr_align); + // Return 0 unconditionally from the intrinsic call; + // we can never unwind. + let ret_align = bx.tcx().data_layout.i32_align.abi; + bx.store(bx.const_i32(0), dest, ret_align); } else if wants_msvc_seh(bx.sess()) { codegen_msvc_try(bx, func, data, local_ptr, dest); } else { From 85ec3ecd137251d522d1991ac60ed484724f2123 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 26 Dec 2019 10:37:48 -0500 Subject: [PATCH 3/9] Test catch_unwind vanishing We execpt the try intrinsic to be a direct call if in -Cpanic=abort mode, and that catch_unwind optimizes out if calling a function that does not unwind. --- src/test/codegen/catch-unwind.rs | 19 +++++++++++++++++++ src/test/codegen/try-panic-abort.rs | 17 +++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 src/test/codegen/catch-unwind.rs create mode 100644 src/test/codegen/try-panic-abort.rs diff --git a/src/test/codegen/catch-unwind.rs b/src/test/codegen/catch-unwind.rs new file mode 100644 index 0000000000000..3c9bc35d1c8bd --- /dev/null +++ b/src/test/codegen/catch-unwind.rs @@ -0,0 +1,19 @@ +// compile-flags: -O + +#![crate_type = "lib"] + +extern "C" { + fn bar(); +} + +// CHECK-LABEL: @foo +#[no_mangle] +pub unsafe fn foo() -> i32 { + // CHECK: call void @bar + // CHECK: ret i32 0 + std::panic::catch_unwind(|| { + bar(); + 0 + }) + .unwrap() +} diff --git a/src/test/codegen/try-panic-abort.rs b/src/test/codegen/try-panic-abort.rs new file mode 100644 index 0000000000000..9bc89a321576c --- /dev/null +++ b/src/test/codegen/try-panic-abort.rs @@ -0,0 +1,17 @@ +// compile-flags: -C panic=abort -O + +#![crate_type = "lib"] +#![feature(unwind_attributes, core_intrinsics)] + +extern "C" { + #[unwind(allow)] + fn bar(data: *mut u8); +} + +// CHECK-LABEL: @foo +#[no_mangle] +pub unsafe fn foo() -> i32 { + // CHECK: call void @bar + // CHECK: ret i32 0 + std::intrinsics::r#try(|x| bar(x), 0 as *mut u8, 0 as *mut u8) +} From 310903629389c964f8d1532a5c43f662d1d98a8e Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Thu, 26 Dec 2019 10:49:16 -0500 Subject: [PATCH 4/9] Ignore PAL lint for std::panicking --- src/tools/tidy/src/pal.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs index dcd4c9e8ef7d9..31fc6f10e8296 100644 --- a/src/tools/tidy/src/pal.rs +++ b/src/tools/tidy/src/pal.rs @@ -59,6 +59,8 @@ const EXCEPTION_PATHS: &[&str] = &[ "src/libstd/sys_common/mod.rs", "src/libstd/sys_common/net.rs", "src/libstd/sys_common/backtrace.rs", + // panic_unwind shims + "src/libstd/panicking.rs", "src/libterm", // Not sure how to make this crate portable, but test crate needs it. "src/libtest", // Probably should defer to unstable `std::sys` APIs. "src/libstd/sync/mpsc", // some tests are only run on non-emscripten From f3da0eaba3720bbd72d2e503ec089add25b6a242 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Thu, 26 Dec 2019 10:54:24 -0500 Subject: [PATCH 5/9] Mark cleanup cold --- src/libstd/panicking.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index c9639f999ef10..2941504cbc3b9 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -300,6 +300,11 @@ pub unsafe fn r#try R>(f: F) -> Result> Err(cleanup(payload.assume_init())) }; + // We consider unwinding to be rare, so mark this function as cold. However, + // do not mark it no-inline -- that decision is best to leave to the + // optimizer (in most cases this function is not inlined even as a normal, + // non-cold function, though, as of the writing of this comment). + #[cold] unsafe fn cleanup(mut payload: Payload) -> Box { let obj = crate::mem::transmute(__rust_panic_cleanup(&mut payload as *mut _ as *mut u8)); update_panic_count(-1); From 5e320df95b75207fd501642647199fae0d449a2a Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Thu, 26 Dec 2019 11:17:18 -0500 Subject: [PATCH 6/9] fixup! Inline catching panics into std::catch_unwind --- src/libstd/panicking.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 2941504cbc3b9..71105624428be 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -67,7 +67,6 @@ cfg_if::cfg_if! { extern "C" { /// The payload ptr here is actually the same as the payload ptr for the try /// intrinsic (i.e., is really `*mut [u64; 2]` or `*mut *mut u8`). - #[unwind(allowed)] fn __rust_panic_cleanup(payload: *mut u8) -> core::raw::TraitObject; /// `payload` is actually a `*mut &mut dyn BoxMeUp` but that would cause FFI warnings. From 4ad9a3c4100d674dc6010a0acff3c73e56fc4151 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 26 Dec 2019 19:37:14 +0100 Subject: [PATCH 7/9] Fix some minor issues --- src/libpanic_abort/lib.rs | 5 +++-- src/libpanic_unwind/lib.rs | 5 +++-- src/libstd/panicking.rs | 4 ++-- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/libpanic_abort/lib.rs b/src/libpanic_abort/lib.rs index ebc57860b9d4a..fe9196ef2314b 100644 --- a/src/libpanic_abort/lib.rs +++ b/src/libpanic_abort/lib.rs @@ -17,10 +17,11 @@ #![feature(panic_runtime)] #![feature(staged_api)] #![feature(rustc_attrs)] -#![feature(raw)] + +use core::any::Any; #[rustc_std_internal_symbol] -pub unsafe extern "C" fn __rust_cleanup(_: *mut u8) -> core::raw::TraitObject { +pub unsafe extern "C" fn __rust_panic_cleanup(_: *mut u8) -> *mut (dyn Any + Send + 'static) { unreachable!() } diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs index 7481ce65d6337..ba417d0b014cd 100644 --- a/src/libpanic_unwind/lib.rs +++ b/src/libpanic_unwind/lib.rs @@ -31,6 +31,7 @@ #![feature(panic_runtime)] use alloc::boxed::Box; +use core::any::Any; use core::panic::BoxMeUp; // If adding to this list, you should also look at libstd::panicking's identical @@ -63,10 +64,10 @@ cfg_if::cfg_if! { mod dwarf; #[no_mangle] -pub unsafe extern "C" fn __rust_panic_cleanup(payload: *mut u8) -> core::raw::TraitObject { +pub unsafe extern "C" fn __rust_panic_cleanup(payload: *mut u8) -> *mut (dyn Any + Send + 'static) { let payload = payload as *mut imp::Payload; let payload = *(payload); - core::mem::transmute(imp::cleanup(payload)) + Box::into_raw(imp::cleanup(payload)) } // Entry point for raising an exception, just delegates to the platform-specific diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 71105624428be..71097d5e232eb 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -67,7 +67,7 @@ cfg_if::cfg_if! { extern "C" { /// The payload ptr here is actually the same as the payload ptr for the try /// intrinsic (i.e., is really `*mut [u64; 2]` or `*mut *mut u8`). - fn __rust_panic_cleanup(payload: *mut u8) -> core::raw::TraitObject; + fn __rust_panic_cleanup(payload: *mut u8) -> *mut (dyn Any + Send + 'static); /// `payload` is actually a `*mut &mut dyn BoxMeUp` but that would cause FFI warnings. /// It cannot be `Box` because the other end of this call does not depend @@ -305,7 +305,7 @@ pub unsafe fn r#try R>(f: F) -> Result> // non-cold function, though, as of the writing of this comment). #[cold] unsafe fn cleanup(mut payload: Payload) -> Box { - let obj = crate::mem::transmute(__rust_panic_cleanup(&mut payload as *mut _ as *mut u8)); + let obj = Box::from_raw(__rust_panic_cleanup(&mut payload as *mut _ as *mut u8)); update_panic_count(-1); debug_assert!(update_panic_count(0) == 0); obj From 5be658a62b5291c39897deac07f9c1ccf576b706 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 29 Dec 2019 12:07:44 +0100 Subject: [PATCH 8/9] Ignore broken no-landing-pads test --- src/test/ui/no-landing-pads.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/ui/no-landing-pads.rs b/src/test/ui/no-landing-pads.rs index d9d532106125a..44af25f7f8f48 100644 --- a/src/test/ui/no-landing-pads.rs +++ b/src/test/ui/no-landing-pads.rs @@ -1,6 +1,7 @@ // run-pass // compile-flags: -Z no-landing-pads -C codegen-units=1 // ignore-emscripten no threads support +// ignore-test fails because catch_unwind doesn't work with no-landing-pads use std::thread; From da5b1a4a50d06af068e192858853eda21cbbf385 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Tue, 7 Jan 2020 16:41:59 +0100 Subject: [PATCH 9/9] Apply review feedback --- Cargo.lock | 1 + src/libpanic_abort/Cargo.toml | 1 + src/libpanic_abort/lib.rs | 5 ++++- src/libpanic_unwind/dummy.rs | 2 -- src/libpanic_unwind/emcc.rs | 2 -- src/libpanic_unwind/gcc.rs | 2 -- src/libpanic_unwind/hermit.rs | 2 -- src/libpanic_unwind/lib.rs | 12 +++++++----- src/libpanic_unwind/payload.rs | 21 +++++++++++++++++++++ src/libpanic_unwind/seh.rs | 2 -- src/libstd/panicking.rs | 34 ++++++---------------------------- src/test/ui/no-landing-pads.rs | 24 ------------------------ 12 files changed, 40 insertions(+), 68 deletions(-) create mode 100644 src/libpanic_unwind/payload.rs delete mode 100644 src/test/ui/no-landing-pads.rs diff --git a/Cargo.lock b/Cargo.lock index f3fad1296bfd7..6a08ea2e326fd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2301,6 +2301,7 @@ dependencies = [ name = "panic_abort" version = "0.0.0" dependencies = [ + "cfg-if", "compiler_builtins", "core", "libc", diff --git a/src/libpanic_abort/Cargo.toml b/src/libpanic_abort/Cargo.toml index 2bee0b716c750..8ebd95047ac23 100644 --- a/src/libpanic_abort/Cargo.toml +++ b/src/libpanic_abort/Cargo.toml @@ -14,3 +14,4 @@ doc = false core = { path = "../libcore" } libc = { version = "0.2", default-features = false } compiler_builtins = "0.1.0" +cfg-if = "0.1.8" diff --git a/src/libpanic_abort/lib.rs b/src/libpanic_abort/lib.rs index fe9196ef2314b..6ea818ecef827 100644 --- a/src/libpanic_abort/lib.rs +++ b/src/libpanic_abort/lib.rs @@ -20,8 +20,11 @@ use core::any::Any; +// We need the definition of TryPayload for __rust_panic_cleanup. +include!("../libpanic_unwind/payload.rs"); + #[rustc_std_internal_symbol] -pub unsafe extern "C" fn __rust_panic_cleanup(_: *mut u8) -> *mut (dyn Any + Send + 'static) { +pub unsafe extern "C" fn __rust_panic_cleanup(_: TryPayload) -> *mut (dyn Any + Send + 'static) { unreachable!() } diff --git a/src/libpanic_unwind/dummy.rs b/src/libpanic_unwind/dummy.rs index 30593d3b88af9..4667ede2baad5 100644 --- a/src/libpanic_unwind/dummy.rs +++ b/src/libpanic_unwind/dummy.rs @@ -6,8 +6,6 @@ use alloc::boxed::Box; use core::any::Any; use core::intrinsics; -pub type Payload = *mut u8; - pub unsafe fn cleanup(_ptr: *mut u8) -> Box { intrinsics::abort() } diff --git a/src/libpanic_unwind/emcc.rs b/src/libpanic_unwind/emcc.rs index 2859067c098b3..f77c1f53c4646 100644 --- a/src/libpanic_unwind/emcc.rs +++ b/src/libpanic_unwind/emcc.rs @@ -48,8 +48,6 @@ static EXCEPTION_TYPE_INFO: TypeInfo = TypeInfo { name: b"rust_panic\0".as_ptr(), }; -pub type Payload = *mut u8; - pub unsafe fn cleanup(ptr: *mut u8) -> Box { assert!(!ptr.is_null()); let adjusted_ptr = __cxa_begin_catch(ptr as *mut libc::c_void); diff --git a/src/libpanic_unwind/gcc.rs b/src/libpanic_unwind/gcc.rs index e09ced175051f..fa48db611993f 100644 --- a/src/libpanic_unwind/gcc.rs +++ b/src/libpanic_unwind/gcc.rs @@ -81,8 +81,6 @@ pub unsafe fn panic(data: Box) -> u32 { } } -pub type Payload = *mut u8; - pub unsafe fn cleanup(ptr: *mut u8) -> Box { let my_ep = ptr as *mut Exception; let cause = (*my_ep).cause.take(); diff --git a/src/libpanic_unwind/hermit.rs b/src/libpanic_unwind/hermit.rs index 8ffb4bcd3df23..6bded4dd499bd 100644 --- a/src/libpanic_unwind/hermit.rs +++ b/src/libpanic_unwind/hermit.rs @@ -6,8 +6,6 @@ use alloc::boxed::Box; use core::any::Any; use core::ptr; -pub type Payload = *mut u8; - pub unsafe fn cleanup(_ptr: *mut u8) -> Box { extern "C" { pub fn __rust_abort() -> !; diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs index ba417d0b014cd..adac6ce18e900 100644 --- a/src/libpanic_unwind/lib.rs +++ b/src/libpanic_unwind/lib.rs @@ -34,8 +34,8 @@ use alloc::boxed::Box; use core::any::Any; use core::panic::BoxMeUp; -// If adding to this list, you should also look at libstd::panicking's identical -// list of Payload types and likely add to there as well. +// If adding to this list, you should also look at the list of TryPayload types +// defined in payload.rs and likely add to there as well. cfg_if::cfg_if! { if #[cfg(target_os = "emscripten")] { #[path = "emcc.rs"] @@ -61,12 +61,14 @@ cfg_if::cfg_if! { } } +include!("payload.rs"); + mod dwarf; #[no_mangle] -pub unsafe extern "C" fn __rust_panic_cleanup(payload: *mut u8) -> *mut (dyn Any + Send + 'static) { - let payload = payload as *mut imp::Payload; - let payload = *(payload); +pub unsafe extern "C" fn __rust_panic_cleanup( + payload: TryPayload, +) -> *mut (dyn Any + Send + 'static) { Box::into_raw(imp::cleanup(payload)) } diff --git a/src/libpanic_unwind/payload.rs b/src/libpanic_unwind/payload.rs new file mode 100644 index 0000000000000..1234db7da0f08 --- /dev/null +++ b/src/libpanic_unwind/payload.rs @@ -0,0 +1,21 @@ +// Type definition for the payload argument of the try intrinsic. +// +// This must be kept in sync with the implementations of the try intrinsic. +// +// This file is included by both panic runtimes and libstd. It is part of the +// panic runtime ABI. +cfg_if::cfg_if! { + if #[cfg(target_os = "emscripten")] { + type TryPayload = *mut u8; + } else if #[cfg(target_arch = "wasm32")] { + type TryPayload = *mut u8; + } else if #[cfg(target_os = "hermit")] { + type TryPayload = *mut u8; + } else if #[cfg(all(target_env = "msvc", target_arch = "aarch64"))] { + type TryPayload = *mut u8; + } else if #[cfg(target_env = "msvc")] { + type TryPayload = [u64; 2]; + } else { + type TryPayload = *mut u8; + } +} diff --git a/src/libpanic_unwind/seh.rs b/src/libpanic_unwind/seh.rs index 3fba52eeb285f..4460fba9f6902 100644 --- a/src/libpanic_unwind/seh.rs +++ b/src/libpanic_unwind/seh.rs @@ -264,8 +264,6 @@ pub unsafe fn panic(data: Box) -> u32 { _CxxThrowException(throw_ptr, &mut THROW_INFO as *mut _ as *mut _); } -pub type Payload = [u64; 2]; - pub unsafe fn cleanup(payload: [u64; 2]) -> Box { mem::transmute(raw::TraitObject { data: payload[0] as *mut _, vtable: payload[1] as *mut _ }) } diff --git a/src/libstd/panicking.rs b/src/libstd/panicking.rs index 71097d5e232eb..a8e559e8d783a 100644 --- a/src/libstd/panicking.rs +++ b/src/libstd/panicking.rs @@ -28,30 +28,8 @@ use crate::io::set_panic; #[cfg(test)] use realstd::io::set_panic; -// This must be kept in sync with the implementations in libpanic_unwind. -// -// This is *not* checked in anyway; the compiler does not allow us to use a -// type/macro/anything from panic_unwind, since we're then linking in the -// panic_unwind runtime even during -Cpanic=abort. -// -// Essentially this must be the type of `imp::Payload` in libpanic_unwind. -cfg_if::cfg_if! { - if #[cfg(not(feature = "panic_unwind"))] { - type Payload = (); - } else if #[cfg(target_os = "emscripten")] { - type Payload = *mut u8; - } else if #[cfg(target_arch = "wasm32")] { - type Payload = *mut u8; - } else if #[cfg(target_os = "hermit")] { - type Payload = *mut u8; - } else if #[cfg(all(target_env = "msvc", target_arch = "aarch64"))] { - type Payload = *mut u8; - } else if #[cfg(target_env = "msvc")] { - type Payload = [u64; 2]; - } else { - type Payload = *mut u8; - } -} +// Include the definition of UnwindPayload from libpanic_unwind. +include!("../libpanic_unwind/payload.rs"); // Binary interface to the panic runtime that the standard library depends on. // @@ -67,7 +45,7 @@ cfg_if::cfg_if! { extern "C" { /// The payload ptr here is actually the same as the payload ptr for the try /// intrinsic (i.e., is really `*mut [u64; 2]` or `*mut *mut u8`). - fn __rust_panic_cleanup(payload: *mut u8) -> *mut (dyn Any + Send + 'static); + fn __rust_panic_cleanup(payload: TryPayload) -> *mut (dyn Any + Send + 'static); /// `payload` is actually a `*mut &mut dyn BoxMeUp` but that would cause FFI warnings. /// It cannot be `Box` because the other end of this call does not depend @@ -288,7 +266,7 @@ pub unsafe fn r#try R>(f: F) -> Result> // method of calling a catch panic whilst juggling ownership. let mut data = Data { f: ManuallyDrop::new(f) }; - let mut payload: MaybeUninit = MaybeUninit::uninit(); + let mut payload: MaybeUninit = MaybeUninit::uninit(); let data_ptr = &mut data as *mut _ as *mut u8; let payload_ptr = payload.as_mut_ptr() as *mut _; @@ -304,8 +282,8 @@ pub unsafe fn r#try R>(f: F) -> Result> // optimizer (in most cases this function is not inlined even as a normal, // non-cold function, though, as of the writing of this comment). #[cold] - unsafe fn cleanup(mut payload: Payload) -> Box { - let obj = Box::from_raw(__rust_panic_cleanup(&mut payload as *mut _ as *mut u8)); + unsafe fn cleanup(payload: TryPayload) -> Box { + let obj = Box::from_raw(__rust_panic_cleanup(payload)); update_panic_count(-1); debug_assert!(update_panic_count(0) == 0); obj diff --git a/src/test/ui/no-landing-pads.rs b/src/test/ui/no-landing-pads.rs deleted file mode 100644 index 44af25f7f8f48..0000000000000 --- a/src/test/ui/no-landing-pads.rs +++ /dev/null @@ -1,24 +0,0 @@ -// run-pass -// compile-flags: -Z no-landing-pads -C codegen-units=1 -// ignore-emscripten no threads support -// ignore-test fails because catch_unwind doesn't work with no-landing-pads - -use std::thread; - -static mut HIT: bool = false; - -struct A; - -impl Drop for A { - fn drop(&mut self) { - unsafe { HIT = true; } - } -} - -fn main() { - thread::spawn(move|| -> () { - let _a = A; - panic!(); - }).join().unwrap_err(); - assert!(unsafe { !HIT }); -}