@@ -1454,4 +1454,50 @@ async fn test_is_empty_32_msgs() {
1454
1454
}
1455
1455
}
1456
1456
1457
+ #[ test]
1458
+ #[ cfg( not( panic = "abort" ) ) ]
1459
+ fn drop_all_elements_during_panic ( ) {
1460
+ use std:: sync:: atomic:: AtomicUsize ;
1461
+ use std:: sync:: atomic:: Ordering :: Relaxed ;
1462
+ use tokio:: sync:: mpsc:: UnboundedReceiver ;
1463
+ use tokio:: sync:: mpsc:: UnboundedSender ;
1464
+
1465
+ static COUNTER : AtomicUsize = AtomicUsize :: new ( 0 ) ;
1466
+
1467
+ struct A ( bool ) ;
1468
+ impl Drop for A {
1469
+ // cause a panic when inner value is `true`.
1470
+ fn drop ( & mut self ) {
1471
+ COUNTER . fetch_add ( 1 , std:: sync:: atomic:: Ordering :: Relaxed ) ;
1472
+ if self . 0 {
1473
+ panic ! ( "panic!" )
1474
+ }
1475
+ }
1476
+ }
1477
+
1478
+ fn func ( tx : UnboundedSender < A > , rx : UnboundedReceiver < A > ) {
1479
+ tx. send ( A ( true ) ) . unwrap ( ) ;
1480
+ tx. send ( A ( false ) ) . unwrap ( ) ;
1481
+ tx. send ( A ( false ) ) . unwrap ( ) ;
1482
+
1483
+ drop ( rx) ;
1484
+
1485
+ // `mpsc::Rx`'s drop is called and gets panicked while dropping the first value,
1486
+ // but will keep dropping following elements.
1487
+ }
1488
+
1489
+ let ( tx, rx) = mpsc:: unbounded_channel ( ) ;
1490
+
1491
+ let _ = panic:: catch_unwind ( panic:: AssertUnwindSafe ( || {
1492
+ func ( tx. clone ( ) , rx) ;
1493
+ } ) ) ;
1494
+
1495
+ // all A's destructor should be called at this point, even before `mpsc::Chan`'s
1496
+ // drop gets called.
1497
+ assert_eq ! ( COUNTER . load( Relaxed ) , 3 ) ;
1498
+
1499
+ drop ( tx) ;
1500
+ // `mpsc::Chan`'s drop is called, freeing the `Block` memory allocation.
1501
+ }
1502
+
1457
1503
fn is_debug < T : fmt:: Debug > ( _: & T ) { }
0 commit comments