summaryrefslogtreecommitdiffstats
path: root/tests/ui/extern/issue-64655-extern-rust-must-allow-unwind.rs
diff options
context:
space:
mode:
Diffstat (limited to 'tests/ui/extern/issue-64655-extern-rust-must-allow-unwind.rs')
-rw-r--r--tests/ui/extern/issue-64655-extern-rust-must-allow-unwind.rs83
1 files changed, 83 insertions, 0 deletions
diff --git a/tests/ui/extern/issue-64655-extern-rust-must-allow-unwind.rs b/tests/ui/extern/issue-64655-extern-rust-must-allow-unwind.rs
new file mode 100644
index 000000000..3b263e58c
--- /dev/null
+++ b/tests/ui/extern/issue-64655-extern-rust-must-allow-unwind.rs
@@ -0,0 +1,83 @@
+// 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);
+}