]> git.lizzy.rs Git - rust.git/commitdiff
create a drop ladder for an array if any value is moved out
authorMikhail Modin <mikhailm1@gmail.com>
Tue, 28 Nov 2017 12:48:23 +0000 (15:48 +0300)
committerMikhail Modin <mikhailm1@gmail.com>
Sat, 2 Dec 2017 19:57:40 +0000 (22:57 +0300)
src/librustc_mir/dataflow/drop_flag_effects.rs
src/librustc_mir/shim.rs
src/librustc_mir/transform/elaborate_drops.rs
src/librustc_mir/util/elaborate_drops.rs
src/test/run-pass/dynamic-drop.rs

index f0ecaea15649c71e4eeae8016fe8e522999e5d7d..1cbe0dcc017f9150361c68e56da0c158766f4cf7 100644 (file)
@@ -61,7 +61,12 @@ fn place_contents_drop_state_cannot_differ<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx,
                                                             place: &mir::Place<'tcx>) -> bool {
     let ty = place.ty(mir, tcx).to_ty(tcx);
     match ty.sty {
-        ty::TyArray(..) | ty::TySlice(..) | ty::TyRef(..) | ty::TyRawPtr(..) => {
+        ty::TyArray(..) => {
+            debug!("place_contents_drop_state_cannot_differ place: {:?} ty: {:?} => false",
+                   place, ty);
+            false
+        }
+        ty::TySlice(..) | ty::TyRef(..) | ty::TyRawPtr(..) => {
             debug!("place_contents_drop_state_cannot_differ place: {:?} ty: {:?} refd => true",
                    place, ty);
             true
index ad228e24e6b13a249c20f5e3980579b4b32a0e0b..9ca044b764806f6a3a2e952e73d13bad28e38798 100644 (file)
@@ -280,6 +280,9 @@ fn deref_subpath(&self, _path: Self::Path) -> Option<Self::Path> {
     fn downcast_subpath(&self, _path: Self::Path, _variant: usize) -> Option<Self::Path> {
         Some(())
     }
+    fn array_subpath(&self, _path: Self::Path, _index: u32, _size: u32) -> Option<Self::Path> {
+        None
+    }
 }
 
 /// Build a `Clone::clone` shim for `self_ty`. Here, `def_id` is `Clone::clone`.
index cb79fc8d7eb27e360337c5b51ba39fa62a92c9ee..b075d2637da9ba53ac1d15a4e1625a90134e46d2 100644 (file)
@@ -257,6 +257,20 @@ fn field_subpath(&self, path: Self::Path, field: Field) -> Option<Self::Path> {
         })
     }
 
+    fn array_subpath(&self, path: Self::Path, index: u32, size: u32) -> Option<Self::Path> {
+        dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| {
+            match p {
+                &Projection {
+                    elem: ProjectionElem::ConstantIndex{offset, min_length: _, from_end: false}, ..
+                } => offset == index,
+                &Projection {
+                    elem: ProjectionElem::ConstantIndex{offset, min_length: _, from_end: true}, ..
+                } => size - offset == index,
+                _ => false
+            }
+        })
+    }
+
     fn deref_subpath(&self, path: Self::Path) -> Option<Self::Path> {
         dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| {
             match p {
index e7d1e5a9ccc74c1834e7e8e1352ed231f9a50f07..3331bc9e59e0b44078909998f9a18a2ff5ec8aeb 100644 (file)
@@ -19,7 +19,7 @@
 use rustc_data_structures::indexed_vec::Idx;
 use util::patch::MirPatch;
 
-use std::iter;
+use std::{iter, u32};
 
 #[derive(Debug, PartialEq, Eq, Copy, Clone)]
 pub enum DropFlagState {
@@ -95,6 +95,7 @@ pub trait DropElaborator<'a, 'tcx: 'a> : fmt::Debug {
     fn field_subpath(&self, path: Self::Path, field: Field) -> Option<Self::Path>;
     fn deref_subpath(&self, path: Self::Path) -> Option<Self::Path>;
     fn downcast_subpath(&self, path: Self::Path, variant: usize) -> Option<Self::Path>;
+    fn array_subpath(&self, path: Self::Path, index: u32, size: u32) -> Option<Self::Path>;
 }
 
 #[derive(Debug)]
@@ -632,8 +633,8 @@ fn drop_loop(&mut self,
         loop_block
     }
 
-    fn open_drop_for_array(&mut self, ety: Ty<'tcx>) -> BasicBlock {
-        debug!("open_drop_for_array({:?})", ety);
+    fn open_drop_for_array(&mut self, ety: Ty<'tcx>, opt_size: Option<u64>) -> BasicBlock {
+        debug!("open_drop_for_array({:?}, {:?})", ety, opt_size);
 
         // if size_of::<ety>() == 0 {
         //     index_based_loop
@@ -641,9 +642,27 @@ fn open_drop_for_array(&mut self, ety: Ty<'tcx>) -> BasicBlock {
         //     ptr_based_loop
         // }
 
-        let tcx = self.tcx();
+        if let Some(size) = opt_size {
+            assert!(size <= (u32::MAX as u64),
+                    "move out check doesn't implemented for array bigger then u32");
+            let size = size as u32;
+            let fields: Vec<(Place<'tcx>, Option<D::Path>)> = (0..size).map(|i| {
+                (self.place.clone().elem(ProjectionElem::ConstantIndex{
+                    offset: i,
+                    min_length: size,
+                    from_end: false
+                }),
+                 self.elaborator.array_subpath(self.path, i, size))
+            }).collect();
+
+            if fields.iter().any(|(_,path)| path.is_some()) {
+                let (succ, unwind) = self.drop_ladder_bottom();
+                return self.drop_ladder(fields, succ, unwind).0
+            }
+        }
 
         let move_ = |place: &Place<'tcx>| Operand::Move(place.clone());
+        let tcx = self.tcx();
         let size = &Place::Local(self.new_temp(tcx.types.usize));
         let size_is_zero = &Place::Local(self.new_temp(tcx.types.bool));
         let base_block = BasicBlockData {
@@ -779,9 +798,10 @@ fn open_drop<'a>(&mut self) -> BasicBlock {
                 let succ = self.succ;
                 self.complete_drop(Some(DropFlagMode::Deep), succ, unwind)
             }
-            ty::TyArray(ety, _) | ty::TySlice(ety) => {
-                self.open_drop_for_array(ety)
-            }
+            ty::TyArray(ety, size) => self.open_drop_for_array(
+                ety, size.val.to_const_int().and_then(|v| v.to_u64())),
+            ty::TySlice(ety) => self.open_drop_for_array(ety, None),
+
             _ => bug!("open drop from non-ADT `{:?}`", ty)
         }
     }
index 3310d3a89b92b76dab4f60e22cd9cd54a1f74d41..09318e7256fd7c5277641de20bd3eec7dca35d6d 100644 (file)
@@ -10,7 +10,7 @@
 
 // ignore-wasm32-bare compiled with panic=abort by default
 
-#![feature(generators, generator_trait, untagged_unions)]
+#![feature(generators, generator_trait, untagged_unions, slice_patterns, advanced_slice_patterns)]
 
 use std::cell::{Cell, RefCell};
 use std::ops::Generator;
@@ -195,6 +195,33 @@ fn vec_unreachable(a: &Allocator) {
     let _x = vec![a.alloc(), a.alloc(), a.alloc(), return];
 }
 
+fn slice_pattern_first(a: &Allocator) {
+    let[_x, ..] = [a.alloc(), a.alloc(), a.alloc()];
+}
+
+fn slice_pattern_middle(a: &Allocator) {
+    let[_, _x, _] = [a.alloc(), a.alloc(), a.alloc()];
+}
+
+fn slice_pattern_two(a: &Allocator) {
+    let[_x, _, _y, _] = [a.alloc(), a.alloc(), a.alloc(), a.alloc()];
+}
+
+fn slice_pattern_last(a: &Allocator) {
+    let[.., _y] = [a.alloc(), a.alloc(), a.alloc(), a.alloc()];
+}
+
+fn slice_pattern_one_of(a: &Allocator, i: usize) {
+    let array = [a.alloc(), a.alloc(), a.alloc(), a.alloc()];
+    let _x = match i {
+        0 => { let [a, ..] = array; a }
+        1 => { let [_, a, ..] = array; a }
+        2 => { let [_, _, a, _] = array; a }
+        3 => { let [_, _, _, a] = array; a }
+        _ => panic!("unmatched"),
+    };
+}
+
 fn run_test<F>(mut f: F)
     where F: FnMut(&Allocator)
 {
@@ -264,5 +291,14 @@ fn main() {
 
     run_test(|a| mixed_drop_and_nondrop(a));
 
+    run_test(|a| slice_pattern_first(a));
+    run_test(|a| slice_pattern_middle(a));
+    run_test(|a| slice_pattern_two(a));
+    run_test(|a| slice_pattern_last(a));
+    run_test(|a| slice_pattern_one_of(a, 0));
+    run_test(|a| slice_pattern_one_of(a, 1));
+    run_test(|a| slice_pattern_one_of(a, 2));
+    run_test(|a| slice_pattern_one_of(a, 3));
+
     run_test_nopanic(|a| union1(a));
 }