@@ -4,6 +4,7 @@ use pin_utils::{unsafe_pinned, unsafe_unpinned};
4
4
use std:: marker:: PhantomPinned ;
5
5
use std:: pin:: Pin ;
6
6
use std:: ptr;
7
+ use std:: thread:: panicking;
7
8
8
9
/// Combinator for the
9
10
/// [`FutureTestExt::assert_unmoved`](super::FutureTestExt::assert_unmoved)
@@ -49,7 +50,48 @@ impl<Fut: Future> Future for AssertUnmoved<Fut> {
49
50
50
51
impl < Fut > Drop for AssertUnmoved < Fut > {
51
52
fn drop ( & mut self ) {
52
- let cur_this = & * self as * const Self ;
53
- assert_eq ! ( self . this_ptr, cur_this, "Future moved before drop" ) ;
53
+ // If the thread is panicking then we can't panic again as that will
54
+ // cause the process to be aborted.
55
+ if !panicking ( ) && !self . this_ptr . is_null ( ) {
56
+ let cur_this = & * self as * const Self ;
57
+ assert_eq ! ( self . this_ptr, cur_this, "Future moved before drop" ) ;
58
+ }
59
+ }
60
+ }
61
+
62
+ #[ cfg( test) ]
63
+ mod tests {
64
+ use futures_core:: future:: Future ;
65
+ use futures_core:: task:: Poll ;
66
+ use futures_util:: future:: empty;
67
+ use futures_util:: task:: noop_local_waker;
68
+ use std:: pin:: Pin ;
69
+
70
+ use super :: AssertUnmoved ;
71
+
72
+ #[ test]
73
+ fn dont_panic_when_not_polled ( ) {
74
+ // This shouldn't panic.
75
+ let future = AssertUnmoved :: new ( empty :: < ( ) > ( ) ) ;
76
+ drop ( future) ;
77
+ }
78
+
79
+ #[ test]
80
+ #[ should_panic( expected = "Future moved between poll calls" ) ]
81
+ fn dont_double_panic ( ) {
82
+ // This test should only panic, not abort the process.
83
+ let waker = noop_local_waker ( ) ;
84
+
85
+ // First we allocate the future on the stack and poll it.
86
+ let mut future = AssertUnmoved :: new ( empty :: < ( ) > ( ) ) ;
87
+ let pinned_future = unsafe { Pin :: new_unchecked ( & mut future) } ;
88
+ assert_eq ! ( pinned_future. poll( & waker) , Poll :: Pending ) ;
89
+
90
+ // Next we move it back to the heap and poll it again. This second call
91
+ // should panic (as the future is moved), but we shouldn't panic again
92
+ // whilst dropping `AssertUnmoved`.
93
+ let mut future = Box :: new ( future) ;
94
+ let pinned_boxed_future = unsafe { Pin :: new_unchecked ( & mut * future) } ;
95
+ assert_eq ! ( pinned_boxed_future. poll( & waker) , Poll :: Pending ) ;
54
96
}
55
97
}
0 commit comments