]> git.lizzy.rs Git - rust.git/commitdiff
VecDeque: drop remaining items on destructor panic
authorJonas Schievink <jonasschievink@gmail.com>
Wed, 11 Dec 2019 18:38:45 +0000 (19:38 +0100)
committerJonas Schievink <jonasschievink@gmail.com>
Wed, 11 Dec 2019 18:38:45 +0000 (19:38 +0100)
src/liballoc/collections/vec_deque.rs
src/liballoc/tests/vec_deque.rs

index 7795083e0580cc2d8f2fbff8081a60cd4b85c897..6e644dced163f69f907d69b755702487b7e7e3e3 100644 (file)
@@ -144,11 +144,21 @@ fn clone_from(&mut self, other: &Self) {
 #[stable(feature = "rust1", since = "1.0.0")]
 unsafe impl<#[may_dangle] T> Drop for VecDeque<T> {
     fn drop(&mut self) {
+        struct Dropper<'a, T>(&'a mut [T]);
+
+        impl<'a, T> Drop for Dropper<'a, T> {
+            fn drop(&mut self) {
+                unsafe {
+                    ptr::drop_in_place(self.0);
+                }
+            }
+        }
+
         let (front, back) = self.as_mut_slices();
         unsafe {
+            let _back_dropper = Dropper(back);
             // use drop for [T]
             ptr::drop_in_place(front);
-            ptr::drop_in_place(back);
         }
         // RawVec handles deallocation
     }
index ebcc832017172ed333c6c490b31a7e8b58396e1e..1ab3694a3ca6171518abe886d99a7fa338f93c20 100644 (file)
@@ -2,6 +2,7 @@
 use std::collections::{vec_deque::Drain, VecDeque};
 use std::fmt::Debug;
 use std::mem::size_of;
+use std::panic::catch_unwind;
 use std::{isize, usize};
 
 use crate::hash;
@@ -709,6 +710,39 @@ fn drop(&mut self) {
     assert_eq!(unsafe { DROPS }, 4);
 }
 
+#[test]
+fn test_drop_panic() {
+    static mut DROPS: i32 = 0;
+
+    struct D(bool);
+
+    impl Drop for D {
+        fn drop(&mut self) {
+            unsafe {
+                DROPS += 1;
+            }
+
+            if self.0 {
+                panic!("panic in `drop`");
+            }
+        }
+    }
+
+    let mut q = VecDeque::new();
+    q.push_back(D(false));
+    q.push_back(D(false));
+    q.push_back(D(false));
+    q.push_back(D(false));
+    q.push_back(D(false));
+    q.push_front(D(false));
+    q.push_front(D(false));
+    q.push_front(D(true));
+
+    catch_unwind(move || drop(q)).ok();
+
+    assert_eq!(unsafe { DROPS }, 8);
+}
+
 #[test]
 fn test_reserve_grow() {
     // test growth path A