diff --git a/src/librustc_mir/dataflow/drop_flag_effects.rs b/src/librustc_mir/dataflow/drop_flag_effects.rs index f0ecaea15649c..1cbe0dcc017f9 100644 --- a/src/librustc_mir/dataflow/drop_flag_effects.rs +++ b/src/librustc_mir/dataflow/drop_flag_effects.rs @@ -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 diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs index ad228e24e6b13..9ca044b764806 100644 --- a/src/librustc_mir/shim.rs +++ b/src/librustc_mir/shim.rs @@ -280,6 +280,9 @@ impl<'a, 'tcx> DropElaborator<'a, 'tcx> for DropShimElaborator<'a, 'tcx> { fn downcast_subpath(&self, _path: Self::Path, _variant: usize) -> Option { Some(()) } + fn array_subpath(&self, _path: Self::Path, _index: u32, _size: u32) -> Option { + None + } } /// Build a `Clone::clone` shim for `self_ty`. Here, `def_id` is `Clone::clone`. diff --git a/src/librustc_mir/transform/elaborate_drops.rs b/src/librustc_mir/transform/elaborate_drops.rs index cb79fc8d7eb27..b075d2637da9b 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/src/librustc_mir/transform/elaborate_drops.rs @@ -257,6 +257,20 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> { }) } + fn array_subpath(&self, path: Self::Path, index: u32, size: u32) -> Option { + 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 { dataflow::move_path_children_matching(self.ctxt.move_data(), path, |p| { match p { diff --git a/src/librustc_mir/util/elaborate_drops.rs b/src/librustc_mir/util/elaborate_drops.rs index e7d1e5a9ccc74..3331bc9e59e0b 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/src/librustc_mir/util/elaborate_drops.rs @@ -19,7 +19,7 @@ use rustc::ty::util::IntTypeExt; 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; fn deref_subpath(&self, path: Self::Path) -> Option; fn downcast_subpath(&self, path: Self::Path, variant: usize) -> Option; + fn array_subpath(&self, path: Self::Path, index: u32, size: u32) -> Option; } #[derive(Debug)] @@ -632,8 +633,8 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> 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) -> BasicBlock { + debug!("open_drop_for_array({:?}, {:?})", ety, opt_size); // if size_of::() == 0 { // index_based_loop @@ -641,9 +642,27 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> // 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)> = (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 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> 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) } } diff --git a/src/test/run-pass/dynamic-drop.rs b/src/test/run-pass/dynamic-drop.rs index 3310d3a89b92b..09318e7256fd7 100644 --- a/src/test/run-pass/dynamic-drop.rs +++ b/src/test/run-pass/dynamic-drop.rs @@ -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(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)); }