rust/tests/ui/extern/issue-64655-extern-rust-must-allow-unwind.rs
2024-02-16 20:02:50 +00:00

84 lines
2.8 KiB
Rust

//@ run-pass
//@ needs-unwind
//@ ignore-emscripten no threads support
// rust-lang/rust#64655: with panic=unwind, a panic from a subroutine
// should still run destructors as it unwinds the stack. However,
// bugs with how the nounwind LLVM attribute was applied led to this
// simple case being mishandled *if* you had optimization *and* fat
// LTO turned on.
// This test is the closest thing to a "regression test" we can do
// without actually spawning subprocesses and comparing stderr
// results.
//
// This test takes the code from the above issue and adapts it to
// better fit our test infrastructure:
//
// * Instead of relying on `println!` to observe whether the destructor
// is run, we instead run the code in a spawned thread and
// communicate the destructor's operation via a synchronous atomic
// in static memory.
//
// * To keep the output from confusing a casual user, we override the
// panic hook to be a no-op (rather than printing a message to
// stderr).
//
// (pnkfelix has confirmed by hand that these additions do not mask
// the underlying bug.)
// LTO settings cannot be combined with -C prefer-dynamic
//@ no-prefer-dynamic
// The revisions combine each lto setting with each optimization
// setting; pnkfelix observed three differing behaviors at opt-levels
// 0/1/2+3 for this test, so it seems prudent to be thorough.
//@ revisions: no0 no1 no2 no3 thin0 thin1 thin2 thin3 fat0 fat1 fat2 fat3
//@[no0]compile-flags: -C opt-level=0 -C lto=no
//@[no1]compile-flags: -C opt-level=1 -C lto=no
//@[no2]compile-flags: -C opt-level=2 -C lto=no
//@[no3]compile-flags: -C opt-level=3 -C lto=no
//@[thin0]compile-flags: -C opt-level=0 -C lto=thin
//@[thin1]compile-flags: -C opt-level=1 -C lto=thin
//@[thin2]compile-flags: -C opt-level=2 -C lto=thin
//@[thin3]compile-flags: -C opt-level=3 -C lto=thin
//@[fat0]compile-flags: -C opt-level=0 -C lto=fat
//@[fat1]compile-flags: -C opt-level=1 -C lto=fat
//@[fat2]compile-flags: -C opt-level=2 -C lto=fat
//@[fat3]compile-flags: -C opt-level=3 -C lto=fat
fn main() {
use std::sync::atomic::{AtomicUsize, Ordering};
static SHARED: AtomicUsize = AtomicUsize::new(0);
assert_eq!(SHARED.fetch_add(0, Ordering::SeqCst), 0);
let old_hook = std::panic::take_hook();
std::panic::set_hook(Box::new(|_| { } )); // no-op on panic.
let handle = std::thread::spawn(|| {
struct Droppable;
impl Drop for Droppable {
fn drop(&mut self) {
SHARED.fetch_add(1, Ordering::SeqCst);
}
}
let _guard = Droppable;
None::<()>.expect("???");
});
let wait = handle.join();
// reinstate handler to ease observation of assertion failures.
std::panic::set_hook(old_hook);
assert!(wait.is_err());
assert_eq!(SHARED.fetch_add(0, Ordering::SeqCst), 1);
}