@@ -111,6 +111,8 @@ where
111111 }
112112
113113 pub ( super ) fn drop_join_handle_slow ( self ) {
114+ let mut maybe_panic = None ;
115+
114116 // Try to unset `JOIN_INTEREST`. This must be done as a first step in
115117 // case the task concurrently completed.
116118 if self . header ( ) . state . unset_join_interested ( ) . is_err ( ) {
@@ -119,11 +121,20 @@ where
119121 // the scheduler or `JoinHandle`. i.e. if the output remains in the
120122 // task structure until the task is deallocated, it may be dropped
121123 // by a Waker on any arbitrary thread.
122- self . core ( ) . stage . drop_future_or_output ( ) ;
124+ let panic = panic:: catch_unwind ( panic:: AssertUnwindSafe ( || {
125+ self . core ( ) . stage . drop_future_or_output ( ) ;
126+ } ) ) ;
127+ if let Err ( panic) = panic {
128+ maybe_panic = Some ( panic) ;
129+ }
123130 }
124131
125132 // Drop the `JoinHandle` reference, possibly deallocating the task
126133 self . drop_reference ( ) ;
134+
135+ if let Some ( panic) = maybe_panic {
136+ panic:: resume_unwind ( panic) ;
137+ }
127138 }
128139
129140 // ===== waker behavior =====
@@ -182,17 +193,25 @@ where
182193 // ====== internal ======
183194
184195 fn complete ( self , output : super :: Result < T :: Output > , is_join_interested : bool ) {
185- if is_join_interested {
186- // Store the output. The future has already been dropped
187- //
188- // Safety: Mutual exclusion is obtained by having transitioned the task
189- // state -> Running
190- let stage = & self . core ( ) . stage ;
191- stage. store_output ( output) ;
192-
193- // Transition to `Complete`, notifying the `JoinHandle` if necessary.
194- transition_to_complete ( self . header ( ) , stage, & self . trailer ( ) ) ;
195- }
196+ // We catch panics here because dropping the output may panic.
197+ //
198+ // Dropping the output can also happen in the first branch inside
199+ // transition_to_complete.
200+ let _ = panic:: catch_unwind ( panic:: AssertUnwindSafe ( || {
201+ if is_join_interested {
202+ // Store the output. The future has already been dropped
203+ //
204+ // Safety: Mutual exclusion is obtained by having transitioned the task
205+ // state -> Running
206+ let stage = & self . core ( ) . stage ;
207+ stage. store_output ( output) ;
208+
209+ // Transition to `Complete`, notifying the `JoinHandle` if necessary.
210+ transition_to_complete ( self . header ( ) , stage, & self . trailer ( ) ) ;
211+ } else {
212+ drop ( output) ;
213+ }
214+ } ) ) ;
196215
197216 // The task has completed execution and will no longer be scheduled.
198217 //
0 commit comments