|
| 1 | +// run-pass |
| 2 | +// ignore-wasm32-bare compiled with panic=abort by default |
| 3 | +// ignore-emscripten no threads support |
| 4 | + |
| 5 | +// rust-lang/rust#64655: with panic=unwind, a panic from a subroutine |
| 6 | +// should still run destructors as it unwinds the stack. However, |
| 7 | +// bugs with how the nounwind LLVM attribute was applied led to this |
| 8 | +// simple case being mishandled *if* you had optimization *and* fat |
| 9 | +// LTO turned on. |
| 10 | + |
| 11 | +// This test is the closest thing to a "regression test" we can do |
| 12 | +// without actually spawning subprocesses and comparing stderr |
| 13 | +// results. |
| 14 | +// |
| 15 | +// This test takes the code from the above issue and adapts it to |
| 16 | +// better fit our test infrastructure: |
| 17 | +// |
| 18 | +// * Instead of relying on `println!` to observe whether the destructor |
| 19 | +// is run, we instead run the code in a spawned thread and |
| 20 | +// communicate the destructor's operation via a synchronous atomic |
| 21 | +// in static memory. |
| 22 | +// |
| 23 | +// * To keep the output from confusing a casual user, we override the |
| 24 | +// panic hook to be a no-op (rather than printing a message to |
| 25 | +// stderr). |
| 26 | +// |
| 27 | +// (pnkfelix has confirmed by hand that these additions do not mask |
| 28 | +// the underlying bug.) |
| 29 | + |
| 30 | +// LTO settings cannot be combined with -C prefer-dynamic |
| 31 | +// no-prefer-dynamic |
| 32 | + |
| 33 | +// The revisions combine each lto setting with each optimization |
| 34 | +// setting; pnkfelix observed three differing behaviors at opt-levels |
| 35 | +// 0/1/2+3 for this test, so it seems prudent to be thorough. |
| 36 | + |
| 37 | +// revisions: no0 no1 no2 no3 thin0 thin1 thin2 thin3 fat0 fat1 fat2 fat3 |
| 38 | + |
| 39 | +//[no0]compile-flags: -C opt-level=0 -C lto=no |
| 40 | +//[no1]compile-flags: -C opt-level=1 -C lto=no |
| 41 | +//[no2]compile-flags: -C opt-level=2 -C lto=no |
| 42 | +//[no3]compile-flags: -C opt-level=3 -C lto=no |
| 43 | +//[thin0]compile-flags: -C opt-level=0 -C lto=thin |
| 44 | +//[thin1]compile-flags: -C opt-level=1 -C lto=thin |
| 45 | +//[thin2]compile-flags: -C opt-level=2 -C lto=thin |
| 46 | +//[thin3]compile-flags: -C opt-level=3 -C lto=thin |
| 47 | +//[fat0]compile-flags: -C opt-level=0 -C lto=fat |
| 48 | +//[fat1]compile-flags: -C opt-level=1 -C lto=fat |
| 49 | +//[fat2]compile-flags: -C opt-level=2 -C lto=fat |
| 50 | +//[fat3]compile-flags: -C opt-level=3 -C lto=fat |
| 51 | + |
| 52 | +fn main() { |
| 53 | + use std::sync::atomic::{AtomicUsize, Ordering}; |
| 54 | + |
| 55 | + static SHARED: AtomicUsize = AtomicUsize::new(0); |
| 56 | + |
| 57 | + assert_eq!(SHARED.fetch_add(0, Ordering::SeqCst), 0); |
| 58 | + |
| 59 | + let old_hook = std::panic::take_hook(); |
| 60 | + |
| 61 | + std::panic::set_hook(Box::new(|_| { } )); // no-op on panic. |
| 62 | + |
| 63 | + let handle = std::thread::spawn(|| { |
| 64 | + struct Droppable; |
| 65 | + impl Drop for Droppable { |
| 66 | + fn drop(&mut self) { |
| 67 | + SHARED.fetch_add(1, Ordering::SeqCst); |
| 68 | + } |
| 69 | + } |
| 70 | + |
| 71 | + let _guard = Droppable; |
| 72 | + None::<()>.expect("???"); |
| 73 | + }); |
| 74 | + |
| 75 | + let wait = handle.join(); |
| 76 | + |
| 77 | + // reinstate handler to ease observation of assertion failures. |
| 78 | + std::panic::set_hook(old_hook); |
| 79 | + |
| 80 | + assert!(wait.is_err()); |
| 81 | + |
| 82 | + assert_eq!(SHARED.fetch_add(0, Ordering::SeqCst), 1); |
| 83 | +} |
0 commit comments